zephir.backend.modules_rpc

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

# Source Code for Module zephir.backend.modules_rpc

       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  # modules_rpc.py
       9  #
      10  # fonctions xmlrpc pour la gestion des modules dans Zephir
      11  #
      12  ###########################################################################
      13  """module de gestion des modules Eole
      14  """
      15  from zephir.backend.db_utils import *
      16  from zephir.backend import config
      17  from zephir.backend.config import u, log
      18  from zephir.backend.xmlrpceole import XMLRPCEole as XMLRPC
      19  from zephir.backend.lib_backend import ResourceAuthError, istextfile, cx_pool
      20  from zephir.utils.creolewrap import ZephirDict
      21
      22  # import relatifs aux tables
      23  import sys,os,shutil,time,dico,base64,ConfigParser,traceback,cjson
      24  from hashlib import md5
      25  from zephir.eolerpclib import xmlrpclib, EoleProxy
      26  from creole.cfgparser import EoleDict, eosfunc
      27  from twisted.python import syslog
      28  from twisted.internet import defer
      29
      30  BLANK_MD5 = md5('').hexdigest()
      31
      32 -class RPCModules(XMLRPC):
      33      """serveur XMLRPC zephir pour la gestion des modules Eole
      34      """
      35
      36 -    def __init__(self,parent):
      37          self.dbpool = db_connect()
      38          self.dbpool.noisy = 0
      39          self.parent = parent
      40          # mise à jour des modules si besoin
      41          XMLRPC.__init__(self)
      42
      43 -    def startup(self):
      44          self.old_obs = log.theLogPublisher.observers[0]
      45          new_obs = syslog.SyslogObserver('zephir_backend', options=syslog.DEFAULT_OPTIONS, facility=syslog.DEFAULT_FACILITY)
      46          log.addObserver(new_obs.emit)
      47          log.removeObserver(self.old_obs)
      48          self.xmlrpc_update_modules()
      49
      50 -    def stop(self):
      51          if self.old_obs:
      52              log.removeObserver(log.theLogPublisher.observers[0])
      53              log.addObserver(self.old_obs)
      54
      55 -    def xmlrpc_update_modules(self,cred_user=''):
      56          """vérification de la liste des modules"""
      57          cursor = cx_pool.create()
      58          try:
      59              cursor.execute("""select id, libelle, version from modules""")
      60              modules_actuels = cursor.fetchall()
      61              libelle_modules = [module[1] for module in modules_actuels]
      62          except:
      63              cx_pool.close(cursor)
      64              # Erreur de lecture des modules
      65              log.msg("\nErreur de lecture de la liste des modules\n")
      66              return 0, u("Erreur de lecture de la liste des modules")
      67          cx_pool.close(cursor)
      68          d_list = []
      69          new_modules = []
      70          for version, modules in config.liste_modules.items():
      71              for module in modules:
      72                  # on recrée automatiquement les modules manquants, en dehors des modules Eole 1.X
      73                  if module not in libelle_modules and version > 1:
      74                      try:
      75                          new_modules.append(module)
      76                          d_list.append(self.xmlrpc_add_module("", module, version, True))
      77                      except:
      78                          return 0, u("erreur d'ajout du module %s" % module)
      79          d = defer.DeferredList(d_list, consumeErrors=True)
      80          d.addBoth(self._update_module, new_modules)
      81
      82 -    def _update_module(self, result, new_modules):
      83          # log de la création des modules
      84          for index, libelle in enumerate(new_modules):
      85              if result[index][0] == True:
      86                  log.msg(u"\nNouveau module créé: %s (%s)" % (libelle, result[index][1]))
      87              else:
      88                  log.msg(u"\nErreur de création du module %s : %s" % (libelle, result[index][1]))
      89          if len(new_modules) > 0:
      90              # mise à jour des données du pool de dictionnaires
      91              self.parent.dictpool.update_data()
      92              self.parent.dictpool.reset_modules()
      93              return 1, u("Nouveaux modules : %s" % ", ".join(new_modules))
      94          else:
      95              return 1, u("OK")
      96
      97 -    def _got_modules(self,modules,cred_user):
      98          """Récupération de la table module depuis le backend
      99          """
     100          l=[]
     101          for module in modules:
     102              try:
     103                  self.parent.s_pool.check_mod_credential(cred_user, module[0])
     104              except ResourceAuthError:
     105                  # non autorisé : module suivant
     106                  continue
     107              if module[2] == None:
     108                  version = 1
     109              else:
     110                  version = module[2]
     111              l.append({'id':module[0],'libelle':module[1],'version':version})
     112          return 1,u(l)
     113
     114      ##############################
     115      ## gestion de la table modules
     116      ##############################
     117
     118
     119 -    def xmlrpc_add_module(self, cred_user, libelle, version=3, auto=False):
     120          """ajoute un module dans la base de données et crée l'arborescence correspondante
     121          @param auto: si True, on ne met pas à jour le pool de dictionnaires.
     122                       Limite les traitements au démarrage (update_modules)
     123          """
     124          # on vérifie que les données obligatoires sont remplies
     125          if libelle:
     126              query = """insert into modules (libelle, version) values (%s,%s)"""
     127              params = (libelle, int(version))
     128              # on effectue l'insertion (l'existence est à tester dans l'application cliente)
     129              return self.dbpool.runOperation(query, params).addCallbacks(self._add_module1,db_client_failed,callbackArgs=[libelle, version, auto])
     130          else:
     131              # des attributs manquent
     132              return 0, u("""donnez un libellé""")
     133
     134 -    def _add_module1(self, resultat, libelle, version, auto):
     135          """récupère l'id du module créé"""
     136          # requête pour récupérer l'id
     137          query="""select id from modules where libelle ilike %s"""
     138          return self.dbpool.runQuery(query, (libelle,)).addCallbacks(self._add_module2,db_client_failed,callbackArgs=[libelle,version,auto])
     139
     140 -    def _add_module2(self, row, libelle, version, auto):
     141          """crée la variante standard d'un nouveau module"""
     142          if row ==[]:
     143              return 0,u('erreur de création du module dans la base')
     144          else:
     145              id_module=row[0][0]
     146              # on crée la variante standard du module
     147              query = """insert into variantes (module,libelle) values (%s, 'standard')"""
     148              return self.dbpool.runOperation(query, (int(id_module),)).addCallbacks(self._add_module3,db_client_failed,callbackArgs=[id_module,libelle,version,auto])
     149
     150 -    def _add_module3(self, resultat, id_module, libelle, version, auto):
     151          """récupère l'id de la variante standard"""
     152          query = """select id,module from variantes where module = %s and libelle = 'standard'"""
     153          return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._add_module4,db_client_failed,callbackArgs=[libelle,version,auto])
     154
     155
     156 -    def _add_module4(self,row,libelle,version,auto):
     157          """met en place l'arborescence du nouveau module et de ses variantes"""
     158          if row == []:
     159              return 0,u('erreur de creation de la variante par défaut dans la base')
     160          else:
     161              id_variante = row[0][0]
     162              id_module = row[0][1]
     163              # on créé l'arborescence pour le module
     164              module_dir = os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)
     165              try:
     166                  if not os.path.isdir(module_dir):
     167                      os.makedirs(module_dir)
     168                  # lien du(des) dictionnaire(s)
     169                  if int(version) == 1:
     170                      dico_module = os.path.abspath(config.ROOT_DIR)+'/dictionnaires/dico-%s' % libelle
     171                      os.system('ln -s %s %s' % (dico_module,module_dir+os.sep+'dictionnaire'))
     172                  else:
     173                      # module eole 2
     174                      dico_module=os.path.abspath(config.ROOT_DIR)+'/dictionnaires/%s' % libelle
     175                      if os.path.isdir(dico_module):
     176                          # modules de base eole (ancienne méthode de gestion des dicos)
     177                          os.system('ln -s %s %s' % (dico_module, os.path.join(module_dir,'dicos')))
     178                          # création d'un fichier de valeurs par défaut
     179                          d = EoleDict()
     180                          d.read_dir(os.path.join(module_dir,'dicos'))
     181                      else:
     182                          os.makedirs(os.path.join(module_dir,'dicos'))
     183                  # on crée la variante par défaut (module standard)
     184                  os.makedirs(module_dir+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'dicos')
     185                  os.makedirs(module_dir+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'patchs')
     186                  os.makedirs(module_dir+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'fichiers_perso')
     187                  os.makedirs(module_dir+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'fichiers_zephir')
     188              except:
     189                  traceback.print_exc()
     190                  try:
     191                      shutil.rmtree(module_dir)
     192                  except:
     193                      # aucun répertoire créé
     194                      pass
     195                  query = """delete from variantes where module = %s"""
     196                  self.dbpool.runOperation(query, (int(id_module),))
     197                  query = """delete from modules where id = %s"""
     198                  self.dbpool.runOperation(query, (int(id_module),))
     199                  return 0, u("""erreur de creation de l'arborescence du module %s""" % libelle)
     200              # mise à jour des statistiques
     201              self.parent.s_pool.stats['serv_modules'][str(id_module)] = 0
     202              self.parent.s_pool.stats['serv_variantes'][str(id_variante)] = 0
     203              # mise à jour du pool de dictionnaires si lancé par un utilisateur
     204              if not auto:
     205                  self.parent.dictpool.update_data()
     206              return 1, u(id_module)
     207
     208 -    def xmlrpc_del_module(self,cred_user,id_module):
     209          """supprime un module et ses variantes"""
     210          if int(id_module) >= 0:
     211              self.parent.s_pool.check_mod_credential(cred_user, id_module)
     212              # suppression des variantes dans la base de données
     213              query = "delete from variantes where module = %s"
     214              return self.dbpool.runOperation(query, (int(id_module),)).addCallbacks(self._del_module,db_client_failed,callbackArgs=[id_module])
     215          else:
     216              return 0, u("""donnez l'id d'un module (nombre entier)""")
     217
     218 -    def _del_module(self,retour,id_module):
     219          """supprime de la base les services liés au module"""
     220          query = "delete from services where module = %s"
     221          return self.dbpool.runOperation(query, (int(id_module),)).addCallbacks(self._del_module1,db_client_failed,callbackArgs=[id_module])
     222
     223 -    def _del_module1(self,retour,id_module):
     224          """supprime le module dans la base de données"""
     225          query = "delete from modules where id = %s"
     226          return self.dbpool.runOperation(query, (int(id_module),)).addCallbacks(self._del_module2,db_client_failed,callbackArgs=[id_module])
     227
     228 -    def _del_module2(self,retour,id_module):
     229          """supprime l'arborescence du module dans l'arborescence zephir"""
     230          # mise à jour des statistiques
     231          if str(id_module) in self.parent.s_pool.stats['serv_modules']:
     232              del(self.parent.s_pool.stats['serv_modules'][str(id_module)])
     233          module_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)
     234          try:
     235              shutil.rmtree(module_dir)
     236          except:
     237              return 1,u("""erreur de supression du répertoire du module""")
     238          return 1,u('ok')
     239
     240 -    def xmlrpc_edit_module(self,cred_user,id_module,dico_modifs):
     241          """modification d'un module
     242          cette fonction prend en compte un dictionnaire qui indique les
     243          champs à modifier et leur nouvelle valeur. l'application cliente
     244          doit s'assurer que ces champs existent dans la base"""
     245          self.parent.s_pool.check_mod_credential(cred_user, id_module)
     246          if dico_modifs == {}:
     247              return 1,u("""aucune modification demandée""")
     248          # on vérifie que l'identifiant n'est pas modifié
     249          if 'id' in dico_modifs.keys():
     250              return 0,u("""l'identifiant ne peut pas être modifié""")
     251          # construction de la requête SQL de modification
     252          requete = ["update modules set "]
     253          params = []
     254          for cle in dico_modifs.keys():
     255              requete.append(str(cle))
     256              if cle == 'version':
     257                  requete.append("=%s, ")
     258                  params.append(int(dico_modifs[cle]))
     259              else:
     260                  requete.append("=%s, ")
     261                  params.append(dico_modifs[cle])
     262          string_fin=""" where id=%s"""
     263          params.append(int(id_module))
     264          query="".join(requete)[:-2]
     265          query += string_fin
     266          return self.dbpool.runOperation(query, params).addCallbacks(lambda x:(1,'ok'), db_client_failed)
     267
     268 -    def xmlrpc_get_module(self,cred_user, id_module=None):
     269          """récupère un module précis dans la base ou tous les modules"""
     270          if id_module :
     271              # on récupère le module demandé
     272              query = """select id, libelle, version from modules where id = %s"""
     273              return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._got_modules,db_client_failed,callbackArgs=[cred_user])
     274          else :
     275              # sinon on renvoie tous les modules
     276              query = """select id, libelle, version from modules order by version desc, libelle"""
     277              return self.dbpool.runQuery(query).addCallbacks(self._got_modules,db_client_failed,callbackArgs=[cred_user])
     278
     279 -    def xmlrpc_get_dico(self,cred_user,id_module,id_variante=None):
     280          """récupération du dictionnaire d'un module (valeurs par défaut)"""
     281          # recherche du répertoire ou le dictionnaire est stocké
     282          try:
     283              query = "select version from modules where id = %s"
     284          except:
     285              return 0, u("""donnez l'id d'un module (nombre entier)""")
     286          return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._get_dico,db_client_failed,callbackArgs=[id_module, id_variante])
     287
     288 -    def _get_dico(self,data,id_module,id_variante=None):
     289          # détection version de créole
     290          try:
     291              version = int(data[0][0])
     292          except:
     293              version = 3
     294
     295          try:
     296              # dictionnaire de base du module
     297              if version == 1:
     298                  # module Eole1
     299                  path_dico = os.path.join(os.path.abspath(config.PATH_ZEPHIR), 'modules', str(id_module), 'dictionnaire')
     300                  # envoi des fichiers de configuration au programme de saisie
     301                  try:
     302                      fic = open(path_dico,'r')
     303                  except:
     304                      return 0, u("""dictionnaire non présent""")
     305                  # dictionnaire du module
     306                  lines = fic.readlines()
     307                  fic.close()
     308                  dictionnaire = [ unicode(line, 'ISO-8859-1').encode('UTF-8') for line in lines ]
     309                  # dictionnaires additionnels
     310                  if id_variante is not None:
     311                      dicos = os.path.join(os.path.abspath(config.PATH_ZEPHIR), 'modules', str(id_module), 'variantes', str(id_variante), 'dicos')
     312                      for nom_fic in os.listdir(dicos):
     313                          if nom_fic.endswith('.eol') or nom_fic.endswith('.xml'):
     314                              # ajout d'un dictionnaire
     315                              fic = open(os.path.join(dicos, nom_fic), 'r')
     316                              lines = fic.readlines()
     317                              fic.close()
     318                              dictionnaire.extend([ unicode(line, 'ISO-8859-1').encode('UTF-8') for line in lines ])
     319
     320                  # dictionnaire complet (dictionnaire module + dico locaux)
     321                  dic_complet=dico.DicoEole(dico_zephir=[dictionnaire])
     322
     323                  # si un dico.eol existait déjà, on reprend les anciennes valeurs
     324                  if id_variante is not None:
     325                      path_dicovar = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'dico.eol'
     326                      if os.path.isfile(path_dicovar):
     327                          # on instancie un dictionnaire depuis dico.eol
     328                          # et un autre avec le dictionnaire complet
     329                          f=file(path_dicovar)
     330                          lines = f.readlines()
     331                          f.close()
     332                          data = [ unicode(line, 'ISO-8859-1').encode('UTF-8') for line in lines ]
     333                          # dictionnaire des valeurs actuelles
     334                          dic_actuel=dico.DicoEole(dico_zephir=[data]).ParseDico()
     335                          dico_final = {}
     336                          # on réinsère les données existantes dans le dictionnaire
     337                          for variable, data in dic_complet.dictionnaire.items():
     338                              # si la variable existait déjà, on reprend sa valeur
     339                              if dic_actuel.has_key(data[0]):
     340                                  data[1] = dic_actuel[data[0]][0]
     341                              dico_final[variable]=data
     342                          # on remet le dictionnaire modifié en place dans dico_serveur
     343                          dic_complet.dictionnaire = dico_final
     344
     345                  dicos=[base64.encodestring(dic_complet.save("/dev/null"))]
     346              else:
     347                  # version creole2
     348                  # chargement de configuration pour un serveur Eole2
     349                  path_module = os.path.join(os.path.abspath(config.PATH_ZEPHIR), 'modules', str(id_module))
     350                  path_dico = os.path.join(path_module, 'dicos')
     351                  # définition des dictionnaires à charger
     352                  dict_dirs = [path_dico]
     353                  if id_variante is not None:
     354                      # dictionnaires de la variante si besoin
     355                      dict_dirs.append(os.path.join(path_module,'variantes',str(id_variante),'dicos'))
     356                      if os.path.isdir(os.path.join(path_module,'variantes',str(id_variante),'package')):
     357                          dict_dirs.append(os.path.join(path_module,'variantes',str(id_variante),'package'))
     358                  # création de l'objet ZephirDict et lecture des valeurs existantes
     359                  creole_version = config.CREOLE_VERSIONS[version]
     360                  dict_zeph = ZephirDict(dicos=dict_dirs, confdir=path_dico, mode='config', version=creole_version)
     361                  if creole_version == "creole2":
     362                      if os.path.isfile(os.path.join(path_module, 'module.eol')):
     363                          dict_zeph.dico.load_values(os.path.join(path_module,'module.eol'), check=False)
     364                      # traitement de la variante si demandé
     365                      if id_variante is not None:
     366                          path_var = os.path.join(path_module, 'variantes', str(id_variante), 'dico.eol')
     367                          dict_zeph.dico.load_values(os.path.join(path_var), check=False)
     368                  elif creole_version == "creole3":
     369                      # creole3 : on initialise un 'store' JSON avec les valeurs définies au niveau module/variante
     370                      default_values = {}
     371                      path_mod = os.path.join(path_module, 'module.eol')
     372                      if os.path.isfile(path_mod):
     373                          try:
     374                              store = cjson.decode(file(path_mod).read(), all_unicode=True)
     375                          except cjson.DecodeError:
     376                              store = {}
     377                          default_values.update(store)
     378                      # traitement de la variante si demandé
     379                      if id_variante is not None:
     380                          path_var = os.path.join(path_module, 'variantes', str(id_variante), 'dico.eol')
     381                          if os.path.isfile(path_var):
     382                              try:
     383                                  store = cjson.decode(file(path_var).read(), all_unicode=True)
     384                              except cjson.DecodeError:
     385                                  store = {}
     386                              default_values.update(store)
     387                      if default_values:
     388                          # chargement des valeurs
     389                          dict_zeph.init_from_zephir([str(default_values)])
     390                  dicos = dict_zeph.get_dict()
     391                  if dicos == None:
     392                      dicos = []
     393          except Exception, e:
     394              return 0, u(str(e))
     395
     396          return 1,u(dicos)
     397
     398 -    def xmlrpc_get_vars(self,cred_user,id_module):
     399          """récupération des libellés/familles des variables eole pour un module"""
     400          # recherche du répertoire ou le dictionnaire est stocké
     401          try:
     402              query = "select id,version from modules where id = %s"
     403          except:
     404              return 0, u("""donnez l'id d'un module (nombre entier)""")
     405          return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._get_vars,db_client_failed)
     406
     407 -    def _get_vars(self,data):
     408          # détection version de créole
     409          try:
     410              id_module = int(data[0][0])
     411          except:
     412              return 0, u("""module non trouvé""")
     413          try:
     414              version = int(data[0][1])
     415          except:
     416              version = 3
     417          # dictionnaire de base du module
     418          if version == 1:
     419              # module Eole1
     420              creole_files = [os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'dictionnaire']
     421              # récupération des familles de variables
     422              dicos = []
     423              for dic in creole_files:
     424                  try:
     425                      # lecture du contenu des dictionnaires
     426                      fic = open(dic,'r')
     427                      lines = fic.readlines()
     428                      fic.close()
     429                      data = [ unicode(line, 'ISO-8859-1').encode('UTF-8') for line in lines ]
     430                      # stockage du contenu du dictionnaire
     431                      dicos.append(data)
     432                  except OSError:
     433                      pass
     434              dict_zeph = ZephirDict(dicos=dicos, confdir='', mode='dico', version='creole1')
     435              families = {}
     436          else:
     437              # version creole2
     438              # chargement de configuration pour un serveur Eole2
     439              path_module = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)
     440              path_dico = path_module+os.sep+'dicos'
     441              # définition des dictionnaires à charger
     442              dict_dirs = [path_dico]
     443              # création de l'objet ZephirDict et lecture des valeurs existantes
     444              creole_version = config.CREOLE_VERSIONS[version]
     445              dict_zeph = ZephirDict(dicos=dict_dirs, confdir=path_dico, mode='config', version=creole_version)
     446              families = {}
     447              menu = dict_zeph.get_menu(True)
     448              for family in menu:
     449                  for var in family[2]:
     450                      families[var] = family[0]
     451
     452          # dictionnaire variable, libelle
     453          vars_dict = {}
     454          try:
     455              var_data = dict_zeph.get_first()
     456              while 1:
     457                  if families.has_key(var_data[0]):
     458                      family = families[var_data[0]]
     459                  else:
     460                      family = ''
     461                  vars_dict[var_data[0]] = [var_data[2],family]
     462                  var_data = dict_zeph.get_next()
     463          except:
     464              # on arrive en fin de dictionnaire
     465              pass
     466
     467          return 1,u(vars_dict)
     468
     469 -    def xmlrpc_save_dico(self,cred_user,dico_b64,id_module,id_variante=None,pass_var=""):
     470          """mise à jour du dictionnaire d'un module (valeurs par défaut)"""
     471          # recherche du libellé du module
     472          self.parent.s_pool.check_mod_credential(cred_user, id_module)
     473          if id_variante is not None:
     474              self.parent.s_pool.check_var_credential(cred_user, id_variante)
     475              query = "select modules.id, modules.libelle, modules.version, variantes.owner, variantes.passmd5 \
     476                      from modules,variantes where modules.id=%s and modules.id=variantes.module and variantes.id=%s"
     477              return self.dbpool.runQuery(query, (int(id_module), int(id_variante))).addCallbacks(self._save_dico, db_client_failed, callbackArgs=[cred_user,dico_b64,id_variante,pass_var])
     478          else:
     479              query = """select id, libelle, version from modules where id=%s"""
     480              return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._save_dico, db_client_failed, callbackArgs=[cred_user,dico_b64,id_variante,pass_var])
     481
     482 -    def _save_dico(self,data,cred_user,dico_b64,id_variante=None,pass_var=""):
     483          if data == []:
     484              return 0,u("""module non retrouvé""")
     485          # récupération id et libellé module
     486          id_module = data[0][0]
     487          libelle = data[0][1]
     488          try:
     489              version = int(data[0][2])
     490          except:
     491              version = 3
     492          if id_variante is not None:
     493              # vérification owner/mot de passe
     494              owner = data[0][3]
     495              passmd5 = data[0][4]
     496              if owner != cred_user:
     497                  # vérification du mot de passe
     498                  if passmd5 != pass_var and passmd5 not in [None,'', BLANK_MD5]:
     499                      # mauvais mot de passe
     500                      return 0,u('mot de passe incorrect pour cette variante')
     501          # gestion des différentes versions de creole
     502          if version == 1:
     503              try:
     504                  # décodage du dictionnaire
     505                  dico = base64.decodestring(dico_b64)
     506                  # creole 1 -> encodage en latin-1
     507                  dico = unicode(dico,'UTF-8').encode('ISO-8859-1')
     508                  # sauvegarde
     509                  if id_variante is None:
     510                      path_dico = os.path.abspath(config.ROOT_DIR)+'/dictionnaires/dico-%s' % libelle
     511                  else:
     512                      path_dico = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'dico.eol'
     513                  fic_zephir = open(path_dico,'w')
     514                  fic_zephir.write(dico)
     515                  fic_zephir.close()
     516              except:
     517                  return 0,u("""erreur de sauvegarde du dictionnaire""")
     518          else:
     519              if id_variante is None:
     520                  path_dico = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'module.eol'
     521              else:
     522                  path_dico = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'dico.eol'
     523              creole_version = config.CREOLE_VERSIONS[version]
     524              try:
     525                  values = eval(dico_b64[-1])
     526                  if creole_version == "creole3":
     527                      fic_zephir = file(path_dico, 'w')
     528                      fic_zephir.write(cjson.encode(values))
     529                      fic_zephir.close()
     530                  else:
     531                      parser = ConfigParser.ConfigParser()
     532                      parser._sections = values
     533                      fic_zephir = open(path_dico,'w')
     534                      parser.write(fic_zephir)
     535                      fic_zephir.close()
     536              except:
     537                  return 0,u("""erreur de sauvegarde du dictionnaire""")
     538
     539          return 1,u('ok')
     540
     541 -    def xmlrpc_get_mod_dict(self,cred_user,id_module):
     542          """renvoie la liste des dictionnaires d'un module.
     543          utile pour les modules eole2 (fichier fixé pour les modules eole1)
     544          """
     545          self.parent.s_pool.check_mod_credential(cred_user, id_module)
     546          query = "select id, version from modules where id=%s"
     547          return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._get_mod_dict, db_client_failed)
     548
     549 -    def _get_mod_dict(self,data):
     550          # définition du chemin vers les dictionnaires
     551          id_module, version = data[0]
     552          try:
     553              version = int(version)
     554          except:
     555              version = 3
     556          if version == 1:
     557              # non géré sur creole1
     558              return 1, []
     559          try:
     560              dest_dir=os.path.join(os.path.abspath(config.PATH_MODULES),str(id_module),"dicos")
     561              content = []
     562              # cas d'un répertoire
     563              for dict in os.listdir(dest_dir):
     564                  if dict.endswith('.xml'):
     565                      content.append(dict)
     566              return 1, u(content)
     567          except:
     568              return 0,u("""erreur de parcours du répertoire des dictionnaires""")
     569
     570 -    def xmlrpc_del_mod_dict(self,cred_user,id_module,dico_name):
     571          """renvoie la liste des dictionnaires d'un module.
     572          utile pour les modules eole2 (fichier fixé pour les modules eole1)
     573          """
     574          # définition du chemin vers les dictionnaires
     575          self.parent.s_pool.check_mod_credential(cred_user, id_module)
     576          try:
     577              fic_dest = os.path.join(os.path.abspath(config.PATH_MODULES),str(id_module),"dicos",dico_name)
     578              assert os.path.isfile(fic_dest)
     579          except:
     580              return 0,u("""dictionnaire inexistant %s""" % dico_name)
     581          # on supprime le fichier
     582          try:
     583              os.unlink(fic_dest)
     584              return 1, "OK"
     585          except:
     586              return 0,u("""erreur lors de la suppression du dictionnaire""")
     587
     588      ####################################
     589      ## gestion des variantes des modules
     590      ####################################
     591
     592 -    def _got_variantes(self,variantes,cred_user):
     593          """formate les données lues dans la table variantes pour
     594          l'envoyer à une application zephir (liste de dictionnaires)"""
     595          l=[]
     596          for variante in variantes:
     597              owner = variante[3]
     598              if owner == None:
     599                  owner = ""
     600              try:
     601                  self.parent.s_pool.check_var_credential(cred_user, variante[0])
     602              except ResourceAuthError:
     603                  # non autorisé : module suivant
     604                  continue
     605              l.append({'id':variante[0],'module':variante[1],'libelle':variante[2],'owner':owner})
     606          return 1,u(l)
     607
     608 -    def xmlrpc_copy_variante(self,cred_user,module,id_var_src="",libelle="",passmd5="",keep_perms=False,id_var=""):
     609          """Copie une variante existante sur une nouvelle variante"""
     610          # recherche des données de l'ancienne variante
     611          try:
     612              var_src = int(id_var_src)
     613              module = int(module)
     614              if id_var == "":
     615                  assert libelle != ""
     616              else:
     617                  # écrasement d'une variante existante
     618                  id_var = int(id_var)
     619          except:
     620              return 0, u("""paramètres invalides""")
     621
     622          # lecture du mot de passe et du module de l'ancienne variante
     623          query = """select module,owner,passmd5 from variantes where id=%s"""
     624          return self.dbpool.runQuery(query, (int(var_src),)).addCallbacks(self._copy_variante, db_client_failed,callbackArgs=[cred_user,var_src,libelle,module,passmd5,keep_perms,id_var])
     625
     626 -    def _copy_variante(self,data,cred_user,var_src,libelle,module,passmd5,keep_perms,id_var):
     627          """insertion de la nouvelle variante"""
     628          try:
     629              module_src = data[0][0]
     630              if keep_perms and id_var == "":
     631                  # on veut conserver le propriétaire/mot de passe
     632                  cred_user = data[0][1]
     633                  passmd5 = data[0][2]
     634          except:
     635              # variante créée non trouvée dans la base
     636              return 0,u("""module d'origine non retrouvé dans la base""")
     637
     638          if id_var != "":
     639              # copie sur une variante existante
     640              query = """select * from variantes where id=%s"""
     641              return self.dbpool.runQuery(query, (int(id_var),)).addCallbacks(self._copy_variante3, db_client_failed,callbackArgs=[var_src,module_src,id_var,cred_user,passmd5])
     642          else:
     643              # création d'une copie de variante
     644              query = """insert into variantes (module,libelle,owner,passmd5) values (%s,%s,%s,%s)"""
     645              params = (int(module), libelle, cred_user, passmd5)
     646              # id assigné automatiquement dans postgresql
     647              # on effectue l'insertion
     648              return self.dbpool.runOperation(query, params).addCallbacks(self._copy_variante2, db_client_failed,callbackArgs=[var_src,module_src,libelle,module,id_var,cred_user,passmd5])
     649
     650 -    def _copy_variante2(self,data,var_src,module_src,libelle,module,id_var,cred_user,passmd5):
     651          """recherche de l'id de la variante créée"""
     652
     653          query = """select * from variantes where libelle=%s and module=%s"""
     654          params = (libelle, int(module))
     655          return self.dbpool.runQuery(query, params).addCallbacks(self._copy_variante3, db_client_failed,callbackArgs=[var_src,module_src,id_var,cred_user,passmd5])
     656
     657 -    def _copy_variante3(self,data,var_src,module_src,id_var,cred_user,passmd5):
     658          """copie l'arborescence de la variante source"""
     659          try:
     660              var_dest = data[0][0]
     661              module = data[0][1]
     662              libelle = data[0][2]
     663              owner = data[0][3]
     664              pass_var = data[0][4]
     665          except:
     666              # variante créée non trouvée dans la base
     667              return 0,u("""nouvelle variante non retrouvée dans la base""")
     668          else:
     669              # on recopie l'arborescence de la variante source
     670              rep_src=os.path.abspath(config.PATH_MODULES)+os.sep+str(module_src)+os.sep+'variantes'+os.sep+str(var_src)
     671              rep_dest=os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(var_dest)
     672              try:
     673                  if id_var == "":
     674                      if str(var_dest) not in self.parent.s_pool.stats['serv_variantes']:
     675                          self.parent.s_pool.stats['serv_variantes'][str(var_dest)] = 0
     676                  else:
     677                      # modification d'une variante existante
     678                      if owner != cred_user:
     679                          # vérification du mot de passe
     680                          if passmd5 != pass_var and pass_var not in [None,'', BLANK_MD5]:
     681                              # mauvais mot de passe
     682                              return 0, u("""Mauvais mot de passe pour la variante de destination""")
     683                      shutil.rmtree(rep_dest)
     684                  shutil.copytree(rep_src,rep_dest)
     685              except:
     686                  traceback.print_exc()
     687                  return 0,u("""erreur de copie de l'arborescence de la variante""")
     688
     689          query = """select id, libelle, version from modules where id = %s or id = %s"""
     690          params = (int(module_src), int(module))
     691          return self.dbpool.runQuery(query, params).addCallbacks(self._copy_variante4, db_client_failed,callbackArgs=[var_src, var_dest, module_src, module, id_var])
     692
     693 -    def _copy_variante4(self, data, var_src, var_dest, module_src, module, id_var):
     694          """stocke la concordance entre les variantes si nécessaire"""
     695          if id_var == "":
     696              version_src = version_dest = 0
     697              libelle_src = libelle_dest = ""
     698              try:
     699                  for mod in data:
     700                      if mod[0] == module_src:
     701                          version_src = int(mod[2])
     702                          libelle_src = mod[1][:mod[1].rindex("-")]
     703                      elif mod[0] == module:
     704                          version_dest = int(mod[2])
     705                          libelle_dest = mod[1][:mod[1].rindex("-")]
     706              except:
     707                  log.msg('copie de variante : erreur lors de la recherche des version des modules sources et destination')
     708              # stockage de la liaison entre les 2 variantes si copie pour upgrade entre 2 version d'un module
     709              version_delta = version_dest - version_src
     710              if libelle_src == libelle_dest and version_delta == 1:
     711                  query = """insert into migration_variantes (id_source, id_dest) values (%s,%s)"""
     712                  params = (int(var_src), int(var_dest))
     713                  return self.dbpool.runOperation(query, params).addCallbacks(lambda x:(1, var_dest), db_client_failed)
     714          return 1, var_dest
     715
     716 -    def xmlrpc_add_variante(self,cred_user, module, libelle, pass_var=""):
     717          """ajoute une variante à un module"""
     718          self.parent.s_pool.check_mod_credential(cred_user, module)
     719          # on vérifie qu'on a bien récupéré un module
     720          if module and libelle:
     721              query = """insert into variantes (module,libelle,owner,passmd5) values (%s,%s,%s,%s)"""
     722              params = (int(module), libelle, cred_user, pass_var)
     723              # id assigné automatiquement dans postgresql
     724              # on effectue l'insertion
     725              return self.dbpool.runOperation(query, params).addCallbacks(self._add_variante1, db_client_failed,callbackArgs=[libelle,module])
     726          else:
     727              # des attributs manquent
     728              return 0, u("""donnez un id de module et un libellé""")
     729
     730 -    def _add_variante1(self,data,libelle,module):
     731          """recherche de l'id de la variante créée"""
     732          # on récupère l'id de la variante créée
     733          query = """select * from variantes where libelle ilike %s and module = %s"""
     734          params = (libelle, int(module))
     735          return self.dbpool.runQuery(query, params).addCallbacks(self._add_variante2,db_client_failed)
     736
     737 -    def _add_variante2(self,variante):
     738          """met en place l'arborescence d'une nouvelle variante"""
     739          try:
     740              id_variante = variante[0][0]
     741              module = variante[0][1]
     742              libelle = variante[0][2]
     743          except:
     744              # variante créée non trouvée dans la base
     745              return 0,u("""nouvelle variante non retrouvée dans la base""")
     746          else:
     747              # on créé l'arborescence de la variante dans les modules
     748              os.makedirs(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(id_variante))
     749              os.makedirs(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'patchs')
     750              os.makedirs(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'dicos')
     751              os.makedirs(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'fichiers_perso')
     752              os.makedirs(os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+os.sep+'variantes'+os.sep+str(id_variante)+os.sep+'fichiers_zephir')
     753              # on met à jour les statistiques
     754              self.parent.s_pool.stats['serv_variantes'][str(id_variante)] = 0
     755              self.parent.dictpool.update_data()
     756              return 1,id_variante
     757
     758
     759 -    def xmlrpc_del_variante(self,cred_user,id_variante):
     760          """suppression d'une variante de la base zephir"""
     761          self.parent.s_pool.check_var_credential(cred_user, id_variante)
     762          if id_variante:
     763              query = """select * from variantes where id = %s"""
     764              # on récupère les données de la variante
     765              return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._del_variante, db_client_failed)
     766          else:
     767              return 0,u("""donnez un identifiant de variante""")
     768
     769 -    def _del_variante(self,variante):
     770          """supprime la variante de la base de données"""
     771          try:
     772              id_variante = variante[0][0]
     773              id_module = variante[0][1]
     774              libelle = variante[0][2]
     775          except:
     776              # variante non trouvée dans la base
     777              return 0,u("""variante non trouvée dans la base""")
     778          else:
     779              # on interdit la supression de la variante standard
     780              if libelle == 'standard':
     781                  return 0, u("""la variante standard ne peut pas être supprimée""")
     782              # suppression variante dans la base
     783              query = """delete from variantes where id = %s"""
     784              return self.dbpool.runOperation(query, (int(id_variante),)).addCallbacks(self._del_variante2, db_client_failed,callbackArgs=[id_module,id_variante])
     785
     786 -    def _del_variante2(self,result,id_module,id_variante):
     787          """supression de l'arborescence de la variante"""
     788          del(self.parent.s_pool.stats['serv_variantes'][str(id_variante)])
     789          # ok, on supprime son arborescence dans zephir/modules/variantes/id_variante
     790          variante_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
     791          try:
     792              shutil.rmtree(variante_dir)
     793          except:
     794              # remonter code -1 si supression de répertoire impossible ?
     795              return 0,u("""erreur de supression du répertoire de la variante""")
     796          return 1, u('ok')
     797
     798 -    def xmlrpc_fichiers_variante(self,cred_user,id_variante,show_details=False):
     799          """ retourne la liste des fichiers personnalisés pour cette variante """
     800          self.parent.s_pool.check_var_credential(cred_user, id_variante)
     801          query = """select id,module from variantes where id = %s"""
     802          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._fichiers_zephir,db_client_failed,callbackArgs=[show_details])
     803
     804 -    def _fichiers_zephir(self,data,show_details):
     805          """recherche les fichiers liés à une variante"""
     806          if data == []:
     807              return 0,u("serveur inconnu de zephir")
     808          else:
     809              id_variante = int(data[0][0])
     810              id_module = int(data[0][1])
     811              # répertoire de stockage de la variante sur zephir
     812              variante_dir = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(id_module)+os.sep+'variantes'+os.sep+str(id_variante)
     813              # création du dictionnaire de listes des différents fichiers
     814              dico_res={}
     815              try:
     816                  # dictionnaires additionnels
     817                  liste_dicos = []
     818                  liste_dicos_var = []
     819                  for fic in os.listdir(variante_dir+os.sep+'dicos'):
     820                      if fic.endswith('.eol') or fic.endswith('.xml'):
     821                          liste_dicos_var.append(fic)
     822                  dico_res['dicos_var'] = liste_dicos_var
     823              except OSError:
     824                  dico_res['dicos_var'] = ['répertoire non trouvé !']
     825              try:
     826                  # fichiers templates variante
     827                  dico_res['persos_var'] = (os.listdir(variante_dir+os.sep+'fichiers_perso'))
     828              except OSError:
     829                  dico_res['persos_var'] = ['répertoire non trouvé !']
     830              try:
     831                  # patchs variante
     832                  dico_res['patchs_var'] = os.listdir(variante_dir+os.sep+'patchs')
     833              except OSError:
     834                  dico_res['patchs_var'] = ['répertoire non trouvé !']
     835              try:
     836                  # RPMS variante
     837                  # lecture de la liste des rpms supplémentaires
     838                  fic = open(variante_dir+'/fichiers_zephir/fichiers_variante')
     839                  data = fic.read().split("\n")
     840                  fic.close()
     841                  # recherche de la section des RPMS
     842                  liste_pkg_var = []
     843                  section_rpm = 0
     844                  for ligne in data:
     845                      ligne = ligne.strip()
     846                      if section_rpm == 1:
     847                          # on regarde si on a bien affaire à un paquetage
     848                          if not ligne.startswith('#') and ligne != '':
     849                              # on affiche le nom du paquetage
     850                              liste_pkg_var.append(ligne)
     851                      if ligne == '%%':
     852                          section_rpm = 1
     853                  dico_res['rpms_var'] = liste_pkg_var
     854              except IOError:
     855                  dico_res['rpms_var'] = []
     856              try:
     857                  # fichiers du module
     858                  liste_fic=[]
     859                  try:
     860                      f=open(variante_dir+os.sep+'fichiers_zephir/fichiers_variante')
     861                      old_content=f.read()
     862                      f.close()
     863                      fichiers=old_content.split('%%\n')[0]
     864                  except:
     865                      fichiers=""
     866                  for f_zeph in fichiers.split('\n'):
     867                      if f_zeph.strip().startswith("""/"""):
     868                          f_local = os.path.join(variante_dir,'fichiers_zephir',os.path.basename(f_zeph.strip()))
     869                          if show_details:
     870                              f_info = config.get_file_info(f_local)
     871                              liste_fic.append((f_zeph,f_info))
     872                          elif os.path.exists(f_local):
     873                              liste_fic.append(f_zeph)
     874                  dico_res['fichiers_var'] = liste_fic
     875              except:
     876                  dico_res['fichiers_var'] = ['répertoire non trouvé !']
     877              return 1,u(dico_res)
     878
     879 -    def xmlrpc_get_variante_perms(self, cred_user, id_variante, filepath=""):
     880          """renvoie les informations de permissions associées à un(des) fichier(s)
     881          """
     882          # on recherche le répertoire ou la variante est stockée
     883          query = """select id,module from variantes where id=%s"""
     884          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._get_variante_perms,db_client_failed,callbackArgs=[filepath])
     885
     886 -    def _get_variante_perms(self, data, filepath):
     887          """crée l'archive de la variante et la renvoie"""
     888          if data != []:
     889              id_variante = data[0][0]
     890              id_module = data[0][1]
     891              # répertoire de la variante
     892              var_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
     893          try:
     894              id_var = int(id_variante)
     895
     896          except (KeyError, ValueError):
     897              return 0, u("""variante inconnue : %s""" % str(id_var))
     898          else:
     899              result = self.parent.s_pool.get_file_perms(var_dir, filepath)
     900              return 1, u(result)
     901
     902 -    def xmlrpc_del_variante_perms(self, cred_user, id_variante, filepath="", pass_var=""):
     903          """supprime les informations de permissions associées à un(des) fichier(s)
     904          """
     905          # on recherche le répertoire ou la variante est stockée
     906          query = """select id,module,owner,passmd5 from variantes where id=%s"""
     907          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._del_variante_perms,db_client_failed,callbackArgs=[cred_user,filepath,pass_var])
     908
     909 -    def _del_variante_perms(self, data, cred_user, filepath, pass_var):
     910          """crée l'archive de la variante et la renvoie"""
     911          if data != []:
     912              id_variante = data[0][0]
     913              id_module = data[0][1]
     914              owner = data[0][2]
     915              passmd5 = data[0][3]
     916              # vérification owner/mot de passe
     917              if owner != cred_user:
     918                  # vérification du mot de passe
     919                  if passmd5 != pass_var and passmd5 not in [None,'',BLANK_MD5]:
     920                      # mauvais mot de passe
     921                      return 0,u('mot de passe incorrect pour cette variante')
     922              # répertoire de la variante
     923              var_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
     924          try:
     925              id_var = int(id_variante)
     926          except (KeyError, ValueError):
     927              return 0, u("""variante inconnue : %s""" % str(id_var))
     928          else:
     929              result = self.parent.s_pool.del_file_perms(var_dir, filepath)
     930              return 1, u(result)
     931
     932 -    def xmlrpc_set_variante_perms(self, cred_user, id_variante, rights, pass_var=""):
     933          """enregistre les informations de permissions associées à un(des) fichier(s)
     934          @param rights: dictionnaire au format suviant : {'filepath':[mode,ownership]}
     935          """
     936          # on recherche le répertoire ou la variante est stockée
     937          query = """select id,module,owner,passmd5 from variantes where id=%s"""
     938          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._set_variante_perms,db_client_failed,callbackArgs=[cred_user,rights,pass_var])
     939
     940 -    def _set_variante_perms(self, data, cred_user, rights, pass_var):
     941          """crée l'archive de la variante et la renvoie"""
     942          if data != []:
     943              id_variante = data[0][0]
     944              id_module = data[0][1]
     945              owner = data[0][2]
     946              passmd5 = data[0][3]
     947              # vérification owner/mot de passe
     948              if owner != cred_user:
     949                  # vérification du mot de passe
     950                  if passmd5 != pass_var and passmd5 not in [None,'',BLANK_MD5]:
     951                      # mauvais mot de passe
     952                      return 0,u('mot de passe incorrect pour cette variante')
     953              # répertoire de la variante
     954              var_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
     955          try:
     956              id_var = int(id_variante)
     957          except (KeyError, ValueError):
     958              return 0, u("""variante inconnue : %s""" % str(id_var))
     959          else:
     960              res = self.parent.s_pool.set_file_perms(rights, var_dir)
     961              if res:
     962                  return 1,"OK"
     963              else:
     964                  return 0, u("""erreur d'enregistrement des permissions""")
     965
     966 -    def xmlrpc_get_variante(self,cred_user,id_variante=None):
     967          """récupère la liste d'une variante (ou toutes)"""
     968          if id_variante :
     969              query = """select * from variantes where id=%s"""
     970              return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._got_variantes,db_client_failed,callbackArgs=[cred_user])
     971          else :
     972              query = """select * from variantes order by module desc, id desc"""
     973              return self.dbpool.runQuery(query).addCallbacks(self._got_variantes,db_client_failed,callbackArgs=[cred_user])
     974
     975 -    def xmlrpc_edit_variante(self,cred_user,id_variante,dico_modifs,pass_var=""):
     976          """modification d'une variante
     977          cette fonction prend en compte un dictionnaire qui indique les
     978          champs à modifier et leur nouvelle valeur. l'application cliente
     979          doit s'assurer que ces champs existent dans la base"""
     980          self.parent.s_pool.check_var_credential(cred_user, id_variante)
     981          defer_perms = self.parent.xmlrpc_get_permissions(cred_user, cred_user)
     982          return defer_perms.addCallbacks(self._edit_variante, db_client_failed, callbackArgs=[cred_user,id_variante,dico_modifs,pass_var])
     983
     984 -    def _edit_variante(self,permissions,cred_user,id_variante,dico_modifs,pass_var):
     985          # vérification du propriétaire/mot de passe
     986          query = """select owner,passmd5 from variantes where id=%s"""
     987          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._edit_variante2,db_client_failed,
     988                                                          callbackArgs=[cred_user,permissions,id_variante,dico_modifs,pass_var])
     989
     990 -    def _edit_variante2(self,data,cred_user,permissions,id_variante,dico_modifs,pass_var):
     991          # on vérifie que l'identifiant n'est pas modifié
     992          if dico_modifs == {}:
     993              return 1,u("""aucune modification demandée""")
     994          owner = data[0][0]
     995          passmd5 = data[0][1]
     996          is_admin = False
     997          if permissions[0] == 1 and 4 in permissions[1]:
     998              is_admin = True
     999          # vérification owner/mot de passe
    1000          if owner != cred_user:
    1001              # vérification du mot de passe
    1002              if passmd5 != pass_var and passmd5 not in [None,'',BLANK_MD5]:
    1003                  # mauvais mot de passe
    1004                  return 0,u('mot de passe incorrect pour cette variante')
    1005          if ('id' in dico_modifs.keys()) or ('module' in dico_modifs.keys()):
    1006              return 0,u("""l'identifiant et le module ne peuvent pas être modifiés""")
    1007          if ('owner' in dico_modifs.keys()) or ('passmd5' in dico_modifs.keys()):
    1008              # seul le propriétaire de la variante ou un administrateur a le droit
    1009              # de modifier le mot de passe ou le propriétaire
    1010              if cred_user != owner and not is_admin:
    1011                  return 0,u("""modification du propriétaire ou mot de passe interdits""")
    1012              if 'owner' in dico_modifs.keys():
    1013                  log.msg("nouveau propriétaire pour la variante %s : %s" % (str(id_variante), dico_modifs['owner']))
    1014              if 'passmd5' in dico_modifs.keys():
    1015                  log.msg("changement du mot de passe de la variante %s" % str(id_variante))
    1016          # construction de la requête SQL de modification
    1017          requete = ["update variantes set "]
    1018          params = []
    1019          for cle in dico_modifs.keys():
    1020              requete.append(str(cle))
    1021              requete.append("=%s, ")
    1022              params.append(str(dico_modifs[cle]))
    1023          string_fin=""" where id=%s"""
    1024          params.append(int(id_variante))
    1025          query = "".join(requete)[:-2]
    1026          query += string_fin
    1027          return self.dbpool.runOperation(query, params).addCallbacks(lambda x:(1,'ok'), db_client_failed)
    1028
    1029 -    def xmlrpc_get_migration_infos(self, cred_user, id_module):
    1030          """récupère la liste des variantes d'un module et des variantes de migration définies
    1031          """
    1032          try:
    1033              id_module = int(id_module)
    1034          except:
    1035              return 0,u("identifiant de module invalide")
    1036          self.parent.s_pool.check_mod_credential(cred_user, id_module)
    1037          # récupération des modules
    1038          query = """select id, libelle, version from modules"""
    1039          return self.dbpool.runQuery(query).addCallbacks(self._get_migration_infos,db_client_failed,callbackArgs=[id_module])
    1040
    1041 -    def _get_migration_infos(self, data, id_module):
    1042          # recherche des modules vers lesquels on peut migrer
    1043          mod_src_lib = ""
    1044          mod_src_version = 0
    1045          info_modules = {}
    1046          for module in data:
    1047              if module[0] == id_module:
    1048                  mod_src_lib = module[1]
    1049                  mod_src_version = int(module[2])
    1050                  break
    1051          migration_infos = {}
    1052          if mod_src_version in config.allowed_migrations:
    1053              # pour les modules nécessitant une migration, pas de choix automatique de la variante
    1054              return 1, []
    1055          elif mod_src_version > 1:
    1056              mod_src_name = mod_src_lib[:mod_src_lib.rindex('-')]
    1057              # migration non standard acceptées
    1058              allowed_upgrades = [mod_src_version+1]
    1059              if mod_src_name in config.allowed_upgrades and mod_src_version in config.allowed_upgrades[mod_src_name]:
    1060                  allowed_upgrades.extend(config.allowed_upgrades[mod_src_name][mod_src_version])
    1061              for module in data:
    1062                  mod_name = module[1][:module[1].rindex('-')]
    1063                  mod_version = int(module[2])
    1064                  if mod_name == mod_src_name:
    1065                      if mod_version in allowed_upgrades:
    1066                          info_modules[module[0]] = [module[1],int(module[2])]
    1067                          migration_infos[mod_version] = [[],[]]
    1068              query="""select modules.version, id_source, id_dest, var_dst.module from migration_variantes, modules, variantes as var_dst, variantes as var_src where id_source=var_src.id and var_src.module=%s and var_dst.id=id_dest and modules.id = var_dst.module"""
    1069              return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._get_migration_infos2,db_client_failed,callbackArgs=[id_module, migration_infos, info_modules])
    1070          else:
    1071              return 0,u("module inexistant dans la base")
    1072
    1073 -    def _get_migration_infos2(self, data, id_module, migration_infos, info_modules):
    1074          # correspondances déjà définies
    1075          for var_migration in data:
    1076              if var_migration[0] in migration_infos:
    1077                  migration_infos[var_migration[0]][1].append([var_migration[1], var_migration[2]])
    1078          query = """select id, module from variantes"""
    1079          return self.dbpool.runQuery(query).addCallbacks(self._get_migration_infos3, db_client_failed,callbackArgs=[id_module, migration_infos, info_modules])
    1080
    1081 -    def _get_migration_infos3(self, data, id_module, migration_infos, info_modules):
    1082          # liste des destinations possibles pour chaque module
    1083          for id_var, id_mod in data:
    1084              # on garde seulement les modules de même type
    1085              if id_mod in info_modules:
    1086                  vers_mod = info_modules[id_mod][1]
    1087                  # si migration autorisée
    1088                  if vers_mod in migration_infos:
    1089                      # liste des variantes dispos
    1090                      migration_infos[vers_mod][0].append(id_var)
    1091          result = []
    1092          for vers, data in migration_infos.items():
    1093              result.append((vers, data[0], data[1]))
    1094          return 1, result
    1095
    1096 -    def xmlrpc_variantes_upgrade(self, cred_user, var_src, var_migr):
    1097          """sauvegarde les équivalences d'une variable pour upgrade_auto
    1098          """
    1099          try:
    1100              var_src = int(var_src)
    1101              var_dest = []
    1102              if type(var_migr) != list:
    1103                  var_migr = [var_migr]
    1104              for var in var_migr:
    1105                  var_dest.append(int(var))
    1106          except:
    1107              return 0,u("identifiant de variante invalide")
    1108          self.parent.s_pool.check_var_credential(cred_user, var_src)
    1109          # supression des anciennes correspondances
    1110          query = """delete from migration_variantes where id_source=%s"""
    1111          return self.dbpool.runOperation(query, (int(var_src),)).addCallbacks(self._variantes_upgrade2, db_client_failed, callbackArgs=[var_src, var_dest])
    1112
    1113 -    def _variantes_upgrade2(self, result, var_src, var_dest):
    1114          """sauvegarde les équivalences d'une variable pour upgrade_auto
    1115          """
    1116          if var_dest != []:
    1117              params = []
    1118              inserts = []
    1119              for dst in var_dest:
    1120                  inserts.append('(%s,%s)')
    1121                  params.extend([int(var_src), int(dst)])
    1122              query = """insert into migration_variantes (id_source, id_dest) values %s""" % ", ".join(inserts)
    1123              return self.dbpool.runOperation(query, params).addCallbacks(lambda x:(1,'ok'), db_client_failed)
    1124          else:
    1125              return 1, 'ok'
    1126
    1127 -    def xmlrpc_add_files(self,cred_user,id_variante,dico_files,passwd="",encode=False):
    1128          """ajoute des fichiers, patchs, dictionnaires à une variante
    1129          """
    1130          self.parent.s_pool.check_var_credential(cred_user, id_variante)
    1131          query="select modules.version,variantes.id,variantes.module,variantes.owner,variantes.passmd5 from variantes,modules where variantes.id=%s and modules.id=variantes.module"
    1132          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._add_files,db_client_failed,callbackArgs=[dico_files,cred_user,passwd,encode])
    1133
    1134 -    def _add_files(self,data,dico_files,cred_user,passwd,encode):
    1135          """ajoute des fichiers, patchs, dictionnaires,rpms à une variante
    1136          """
    1137          mod_version = data[0][0]
    1138          try:
    1139              mod_version = int(mod_version)
    1140          except:
    1141              mod_version = 3
    1142          id_variante = data[0][1]
    1143          id_module = data[0][2]
    1144          owner = data[0][3]
    1145          pass_var = data[0][4]
    1146          # si la variante ne nous appartient pas, on interdit la modification si mauvais mot de passe
    1147          if owner != cred_user:
    1148              # vérification du mot de passe
    1149              if passwd != pass_var and pass_var not in [None,'',BLANK_MD5]:
    1150                  # mauvais mot de passe
    1151                  return 0,u('mot de passe incorrect pour cette variante')
    1152          # on met en place les différents types de fichiers
    1153          dest_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
    1154          # dans le cas d'un serveur eole1, on encode le contenu des fichiers en iso8859 si nécessaire
    1155          if mod_version == 1 and encode == True:
    1156              for type_f, files in dico_files.items():
    1157                  if type_f in ['dicos_var','patchs_var','persos_var','fichiers_var']:
    1158                      encoded_files = []
    1159                      for fichier in dico_files[type_f]:
    1160                          content = unicode(base64.decodestring(fichier[1]),config.charset).encode('ISO-8859-1')
    1161                          localpath = ""
    1162                          if len(fichier) == 3:
    1163                              localpath = fichier[2]
    1164                          encoded_files.append([fichier[0], base64.encodestring(content),localpath])
    1165                      dico_files[type_f] = encoded_files
    1166          # on récupère la liste des fichiers à supprimer existante
    1167          liste_remove = []
    1168          if os.path.isfile(dest_dir+os.sep+'fichiers_zephir/removed'):
    1169              f_rem = open(dest_dir+os.sep+'fichiers_zephir/removed')
    1170              for fic in f_rem.read().strip().split('\n'):
    1171                  liste_remove.append(fic)
    1172              f_rem.close()
    1173          def check_removed(nom_dest):
    1174              # on regarde si le fichier était dans la liste des fichiers obsolètes
    1175              if nom_dest in liste_remove:
    1176                  liste_remove.remove(nom_dest)
    1177                  f_rem = open(dest_dir+os.sep+'fichiers_zephir/removed', 'w')
    1178                  f_rem.write('\n'.join(liste_remove))
    1179                  f_rem.close()
    1180          # on vérifie si des paquets non autorisés sont listés
    1181          if dico_files.has_key('rpms_var'):
    1182              use_pool = self.parent.dictpool.check_module(id_module)
    1183              if use_pool:
    1184                  # liste des paquets gérés au niveau variante/module
    1185                  denied = self.parent.dictpool.list_module(id_module, False)
    1186                  denied = set([paq_name for paq_name in denied if not paq_name.endswith('.xml')])
    1187                  # si un paquet demandé est dans la liste, on l'interdit
    1188                  bad_paqs = denied.intersection(set(dico_files['rpms_var']))
    1189                  if bad_paqs:
    1190                      return 0, u("""paquets déjà référencés au niveau du module : %s""" % ', '.join(bad_paqs))
    1191
    1192          # dictionnaires locaux
    1193          for dico in dico_files['dicos_var']:
    1194              try:
    1195                  if dico[0] != "":
    1196                      f=open(dest_dir+os.sep+'dicos'+os.sep+os.path.basename(dico[0].replace("\\","/")),'w')
    1197                      f.write(base64.decodestring(dico[1]))
    1198                      f.close()
    1199              except:
    1200                  return 0,u("erreur de sauvegarde de %s" % dico)
    1201          for template in dico_files['persos_var']:
    1202              try:
    1203                  if template[0] != "":
    1204                      f=open(dest_dir+os.sep+'fichiers_perso'+os.sep+os.path.basename(template[0].replace("\\","/")),'w')
    1205                      f.write(base64.decodestring(template[1]))
    1206                      f.close()
    1207                      check_removed(os.path.join('fichiers_perso', template[0].replace("\\","/")))
    1208              except:
    1209                  return 0,u("erreur de sauvegarde de %s" % template)
    1210          for patch in dico_files['patchs_var']:
    1211              try:
    1212                  if patch[0] != "":
    1213                      f=open(dest_dir+os.sep+'patchs'+os.sep+os.path.basename(patch[0].replace("\\","/")),'w')
    1214                      f.write(base64.decodestring(patch[1]))
    1215                      f.close()
    1216              except:
    1217                  return 0,u("erreur de sauvegarde de %s" % patch)
    1218          # on reprend la liste des fichiers existants
    1219          try:
    1220              f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante')
    1221              old_content=f.read()
    1222              f.close()
    1223              fichiers=old_content.split('%%\n')[0]
    1224              rpms=old_content.split('%%\n')[1]
    1225          except:
    1226              fichiers="""# section 1
    1227  # liste des fichiers à sauvegarder
    1228  # (ne pas modifier sauf pour créer ou mettre à jour la variante)"""
    1229              rpms="""# section 2
    1230  # inscrire les noms des paquetages qui seront installés à la mise à jour du serveur
    1231  # (ils doivent être présents sur le serveur de mise à jour)"""
    1232
    1233          for fichier in dico_files['fichiers_var']:
    1234              # on ajoute le fichier à la liste si il n'est pas déjà présent
    1235              localpath = ""
    1236              if len(fichier) == 3:
    1237                  localpath = fichier[2]
    1238              # on enlève le nom de conteneur si présent
    1239              conteneur = ""
    1240              if '::' in fichier[0]:
    1241                  fic_path, conteneur = fichier[0].split('::')
    1242              else:
    1243                  fic_path = fichier[0]
    1244              # nettoyage du nom de fichier
    1245              nom_fic = fic_path.replace("\\","/")
    1246              # on supprime les séparateurs en fin de ligne
    1247              if fic_path.endswith('/'):
    1248                  nom_fic = fic_path[:-1]
    1249              if fic_path.endswith("\\"):
    1250                  nom_fic = fic_path[:-2]
    1251              if conteneur:
    1252                  nom_final = "%s::%s" % (nom_fic, conteneur)
    1253              else:
    1254                  nom_final = nom_fic
    1255              check_removed(nom_final)
    1256              # on ajoute le fichier à la liste si il n'est pas déjà présent et si il n'est pas dans un sous répertoire
    1257              if nom_final not in fichiers.split('\n') and localpath == "":
    1258                  fichiers = fichiers.strip() + '\n' + nom_final +'\n'
    1259              # on écrit le contenu du fichier
    1260              try:
    1261                  if nom_fic != "":
    1262                      if localpath == "":
    1263                          f=open(os.path.join(dest_dir,'fichiers_zephir',os.path.basename(nom_final)),'w')
    1264                      else:
    1265                          f=open(os.path.join(dest_dir,localpath,os.path.basename(nom_final)),'w')
    1266                      f.write(base64.decodestring(fichier[1]))
    1267                      f.close()
    1268              except:
    1269                  return 0,u("erreur de sauvegarde de %s" % fichier)
    1270
    1271          # rpms
    1272          if dico_files.has_key('rpms_var'):
    1273              for rpm in dico_files['rpms_var']:
    1274                  # on ajoute le rpm si il n'est pas présent
    1275                  if rpm not in rpms.split('\n'):
    1276                      rpms = rpms.strip() + '\n' + rpm +'\n'
    1277
    1278              f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante','w')
    1279              f.write(fichiers+"%%\n"+rpms)
    1280              f.close()
    1281              if self.parent.dictpool.check_module(id_module):
    1282                  # synchronisation des fichiers de dictionnaires
    1283                  # si gérés pour ce module
    1284                  self.parent.dictpool.sync_variante_paqs(id_variante)
    1285          return 1,u("ok")
    1286
    1287 -    def xmlrpc_del_files(self,cred_user,id_variante,dico_files,remove=False,passwd=None):
    1288          """suppression de fichiers, patchs, dictionnaires d'une variante
    1289          """
    1290          self.parent.s_pool.check_var_credential(cred_user, id_variante)
    1291          query = "select id,module,owner,passmd5 from variantes where id=%s"
    1292          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._del_files,db_client_failed,callbackArgs=[dico_files,cred_user,remove,passwd])
    1293
    1294 -    def _del_files(self,data,dico_files,cred_user,remove,passwd):
    1295          """supression de fichiers, patchs, dictionnaires,rpms d'une variante
    1296          """
    1297          id_variante = data[0][0]
    1298          id_module = data[0][1]
    1299          owner = data[0][2]
    1300          pass_var = data[0][3]
    1301          # si la variante ne nous appartient pas, on interdit la modification si mauvais mot de passe
    1302          if owner != cred_user:
    1303              # vérification du mot de passe
    1304              if passwd != pass_var and pass_var not in [None,'',BLANK_MD5]:
    1305                  # mauvais mot de passe
    1306                  return 0,u('mot de passe incorrect pour cette variante')
    1307          # on met en place les différents types de fichiers
    1308          dest_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_variante)
    1309          if remove:
    1310              liste_remove = []
    1311              # on récupère la liste des fichiers à supprimer existante
    1312              if os.path.isfile(dest_dir+os.sep+'fichiers_zephir/removed'):
    1313                  f_rem = open(dest_dir+os.sep+'fichiers_zephir/removed')
    1314                  for fic in f_rem.read().strip().split('\n'):
    1315                      liste_remove.append(fic)
    1316                  f_rem.close()
    1317          # dictionnaires locaux
    1318          for dico in dico_files['dicos_var']:
    1319              try:
    1320                  if dico != "":
    1321                      os.unlink(dest_dir+os.sep+'dicos'+os.sep+dico)
    1322              except:
    1323                  return 0,u("erreur de suppression de %s" % dico)
    1324          for template in dico_files['persos_var']:
    1325              try:
    1326                  if template != "":
    1327                      os.unlink(dest_dir+os.sep+'fichiers_perso'+os.sep+template)
    1328              except:
    1329                  return 0,u("erreur de supression de %s" % template)
    1330              # on supprime les droits associés si nécessaire
    1331              self.parent.s_pool.del_file_perms(dest_dir,'fichiers_perso'+os.sep+template)
    1332              # si demandé, on ajoute le template à la liste des fichiers à supprimer
    1333              # sur le serveur cible
    1334              if remove:
    1335                  fic_sup = os.path.join('fichiers_perso', template)
    1336                  if fic_sup not in liste_remove:
    1337                      liste_remove.append(fic_sup)
    1338
    1339          for patch in dico_files['patchs_var']:
    1340              try:
    1341                  if patch != "":
    1342                      os.unlink(dest_dir+os.sep+'patchs'+os.sep+patch)
    1343              except:
    1344                  return 0,u("erreur de suppression de %s" % patch)
    1345          # on reprend la liste des fichiers existants
    1346          try:
    1347              f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante')
    1348              old_content=f.read()
    1349              f.close()
    1350              fichiers=old_content.split('%%\n')[0]
    1351              rpms=old_content.split('%%\n')[1]
    1352          except:
    1353              fichiers="""# section 1
    1354  # liste des fichiers à sauvegarder pour la variante
    1355  # (ne pas modifier sauf pour créer ou mettre à jour la variante)"""
    1356              rpms="""# section 2
    1357  # inscrire les noms des paquetages qui seront installés à la mise à jour du serveur
    1358  # (ils doivent être présents sur le serveur de mise à jour)"""
    1359          liste=fichiers.split('\n')
    1360
    1361          for fichier in dico_files['fichiers_var']:
    1362              localpath = "fichiers_zephir"
    1363              if type(fichier) in (list, tuple) and len(fichier) == 2:
    1364                  localpath = fichier[1]
    1365                  fichier = fichier[0]
    1366              # on supprime le fichier de la liste
    1367              if fichier in liste:
    1368                  liste.remove(fichier)
    1369                  fichiers = "\n".join(liste)
    1370              fic_path = os.path.join(dest_dir, localpath, os.path.basename(fichier.replace("\\","/")))
    1371              # on efface le fichier
    1372              try:
    1373                  if fichier != "":
    1374                      if os.path.isdir(fic_path):
    1375                          shutil.rmtree(fic_path)
    1376                      elif os.path.isfile(fic_path):
    1377                          os.unlink(fic_path)
    1378              except:
    1379                  f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante','w')
    1380                  f.write(fichiers+"%%\n"+rpms)
    1381                  f.close()
    1382                  return 0,u("erreur de suppression de %s" % fichier)
    1383              # on supprime les droits associés si nécessaire
    1384              fic_sup = os.path.join(localpath,os.path.basename(fichier.replace("\\","/")))
    1385              self.parent.s_pool.del_file_perms(dest_dir,fic_sup,True)
    1386              # si demandé, on ajoute le fichier à la liste des fichiers à supprimer
    1387              # sur le serveur cible
    1388              if remove:
    1389                  fic_rem = fichier.replace("\\","/")
    1390                  if fic_rem not in liste_remove:
    1391                      liste_remove.append(fic_rem)
    1392
    1393          # rpms
    1394          for rpm in dico_files['rpms_var']:
    1395              # on supprime le rpm si il existe
    1396              liste=rpms.split('\n')
    1397              if rpm in liste:
    1398                  liste.remove(rpm)
    1399                  rpms = "\n".join(liste)
    1400              else:
    1401                  f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante','w')
    1402                  f.write(fichiers+"%%\n"+rpms)
    1403                  f.close()
    1404                  return 0,u("rpm non trouvé dans la liste : %s" % rpm)
    1405
    1406          f=open(dest_dir+os.sep+'fichiers_zephir/fichiers_variante','w')
    1407          f.write(fichiers+"%%\n"+rpms)
    1408          f.close()
    1409          if remove and liste_remove:
    1410              # liste des fichiers à supprimer
    1411              f=open(dest_dir+os.sep+'fichiers_zephir/removed', 'w')
    1412              f.write("\n".join(liste_remove))
    1413              f.close()
    1414
    1415          return 1,u("ok")
    1416
    1417 -    def xmlrpc_get_var_file(self,cred_user,id_var,id_module,path,show_details=False):
    1418          """renvoie le contenu d'un fichier de variante"""
    1419          # définition du chemin de la variante
    1420          self.parent.s_pool.check_var_credential(cred_user, id_var)
    1421          query="select variantes.id,variantes.module,modules.version from variantes,modules where variantes.id=%s and modules.id=variantes.module" % id_var
    1422          return self.dbpool.runQuery(query, (int(id_var),)).addCallbacks(self._get_var_file,db_client_failed,callbackArgs=[path,show_details])
    1423
    1424 -    def _get_var_file(self,data,path,show_details):
    1425          id_var = data[0][0]
    1426          id_module = data[0][1]
    1427          mod_version = data[0][2]
    1428          try:
    1429              mod_version = int(mod_version)
    1430          except:
    1431              mod_version = 3
    1432          try:
    1433              dest_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"+os.sep+str(id_var)
    1434          except:
    1435              return 0,u("""lecture du fichier: paramètres non valides""")
    1436          # on lit le fichier
    1437          try:
    1438              # cas d'un répertoire
    1439              if os.path.isdir(dest_dir + os.sep + path):
    1440                  dirfiles = os.listdir(dest_dir + os.sep + path)
    1441                  content = []
    1442                  if show_details:
    1443                      for f in dirfiles:
    1444                          f_local = os.path.join(dest_dir,path,f)
    1445                          f_info = config.get_file_info(f_local)
    1446                          content.append((f,f_info))
    1447                  else:
    1448                      content = dirfiles
    1449                  return 1, u(content)
    1450              else:
    1451                  if istextfile(dest_dir + os.sep + path):
    1452                      f=file(dest_dir + os.sep + path)
    1453                      content=f.read()
    1454                      f.close()
    1455                      # on encode le contenu en base64
    1456                      if mod_version == 1:
    1457                          try:
    1458                              content = unicode(content,'ISO-8859-1').encode(config.charset)
    1459                          except:
    1460                              # le fichier n'est pas en unicode ??
    1461                              log.msg("echec d'encoding du fichier %s provenant d'un serveur eole1" % path)
    1462                      content = base64.encodestring(content)
    1463                  else:
    1464                      content = "BINARY"
    1465                  return 1, content
    1466          except:
    1467              return 0,u("""erreur de lecture du fichier""")
    1468
    1469 -    def xmlrpc_export_variante(self,cred_user,id_variante):
    1470          """envoie le contenu d'une variante sur un autre zephir"""
    1471          # on recherche le répertoire ou la variante est stockée
    1472          query = """select id,module from variantes where id=%s"""
    1473          return self.dbpool.runQuery(query, (int(id_variante),)).addCallbacks(self._export_variante,db_client_failed)
    1474
    1475 -    def _export_variante(self,data):
    1476          """crée l'archive de la variante et le renvoie"""
    1477          if data != []:
    1478              id_variante = data[0][0]
    1479              id_module = data[0][1]
    1480              # répertoire de la variante
    1481              parent_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"
    1482              var_dir=parent_dir+os.sep+str(id_variante)
    1483              # on crée une archive de ce répertoire
    1484              archive=str(time.time())
    1485              if os.path.isdir(var_dir):
    1486                  # création du fichier tar à envoyer
    1487                  cmd_tar = ['cd ',var_dir,';','tar','-chzf','/tmp/'+archive+'.tgz','*']
    1488                  cmd_tar.append('2>&1 >/dev/null')
    1489                  # exécution de tar
    1490                  res=os.system(" ".join(cmd_tar))
    1491                  if res != 0:
    1492                      return 0, u("""erreur de création de l'archive %s.tgz dans /tmp""" % (archive))
    1493                  else:
    1494                      # calcul et stockage d'un checksum md5 de l'archive
    1495                      cmd_checksum = """cd /tmp/; md5sum -b %s.tgz > %s.md5""" % (archive,archive)
    1496                      res=os.system(cmd_checksum)
    1497                      # on stocke en mémoire les données
    1498                      try:
    1499                          # le checksum
    1500                          f = open('/tmp'+os.sep+archive+'.md5')
    1501                          data1 = f.read()
    1502                          f.close()
    1503                          os.unlink('/tmp'+os.sep+archive+'.md5')
    1504                          # l'archive
    1505                          f = open('/tmp'+os.sep+archive+'.tgz')
    1506                          data2 = f.read()
    1507                          f.close()
    1508                          os.unlink('/tmp'+os.sep+archive+'.tgz')
    1509                          return 1,u([archive,base64.encodestring(data1),base64.encodestring(data2)])
    1510                      except Exception, e:
    1511                          return 0,u("""erreur lors de l'envoi de l'archive : %s""" % str(e))
    1512              else:
    1513                  return 0, u("""répertoire %s introuvable""" % var_dir)
    1514          else:
    1515              return 0, u("""variante inexistante""")
    1516
    1517 -    def xmlrpc_import_variante(self,cred_user,pwd_var,id_local,id_distant,zephir_distant,login_distant,pwd_distant):
    1518          """récupère le contenu d'une variante sur un autre zephir"""
    1519          # création d'un proxy vers le serveur zephir distant
    1520          z=EoleProxy("https://%s:%s@%s:%s" % (login_distant,pwd_distant,zephir_distant,config.PORT_ZEPHIR))
    1521          # on vérifie l'existence des variantes des 2 cotés
    1522          try:
    1523              res=z.modules.get_variante(id_distant)
    1524          except:
    1525              return 0,u("""permissions insuffisantes""")
    1526          if res[0] == 0:
    1527              return 0,u("""erreur lors de la recherche de la variante d'origine""")
    1528
    1529          # on recherche le module de la variante locale
    1530          query = """select id, module, owner, passmd5 from variantes where id=%s"""
    1531          return self.dbpool.runQuery(query, (int(id_local),)).addCallbacks(self._import_variante,db_client_failed,callbackArgs=[z,id_distant,cred_user,pwd_var])
    1532
    1533 -    def _import_variante(self,data,proxy,id_distant,cred_user,pwd_var):
    1534          """demande l'envoi de l'archive et met en place les fichiers"""
    1535          if data == []:
    1536              return 0, u("""variante locale non trouvée""")
    1537          else:
    1538              id_variante = data[0][0]
    1539              id_module = data[0][1]
    1540              owner = data[0][2]
    1541              passmd5 = data[0][3]
    1542              # on vérifie le mot de passe de la variante
    1543              if owner != cred_user and pwd_var != passmd5:
    1544                  return 0,u("""mauvais mot de passe de variante""")
    1545              else:
    1546                  # définition du chemin de destination
    1547                  parent_dir=os.path.abspath(config.PATH_MODULES)+os.sep+str(id_module)+os.sep+"variantes"
    1548                  var_dir = parent_dir+os.sep+str(id_variante)
    1549                  # on regarde si des fichiers existent déjà
    1550                  if not os.path.exists(var_dir):
    1551                      return 0,u("""répertoire de la variante de destination non trouvé""")
    1552                  # onrécupère les données de la variante source
    1553                  res=proxy.modules.export_variante(id_distant)
    1554                  if res[0]==0:
    1555                      return 0,u("""erreur lors de la récupération de la variante""")
    1556                  else:
    1557                      # nom de l'archive
    1558                      archive=res[1][0]
    1559                      # somme md5
    1560                      var_data=base64.decodestring(res[1][1])
    1561                      # contenu de l'archive
    1562                      md5_data=base64.decodestring(res[1][2])
    1563                      try:
    1564                          # on supprime l'ancien répertoire de la variante
    1565                          shutil.rmtree(var_dir)
    1566                          # on recrée un répertoire vide
    1567                          os.makedirs(var_dir)
    1568                          # on recrée l'archive et le fichier md5
    1569                          f=open(var_dir+os.sep+archive+'.tgz','w')
    1570                          f.write(md5_data)
    1571                          f.close()
    1572                          f=open(var_dir+os.sep+archive+'.md5','w')
    1573                          f.write(var_data)
    1574                          f.close()
    1575                          # on vérifie la somme md5
    1576                          cmd_md5 = """cd %s; md5sum -c %s.md5 2>&1 > /dev/null""" % (var_dir,archive)
    1577                          res=os.system(cmd_md5)
    1578                          if res != 0:
    1579                              return 0,u("""archive corrompue""")
    1580                          # on décompresse l'archive
    1581                          cmd_tar = """cd %s ; tar -xzf %s.tgz > /dev/null""" % (var_dir,archive)
    1582                          res=os.system(cmd_tar)
    1583                          if res != 0:
    1584                              return 0,u("""erreur de décompression de l'archive""")
    1585                          # on supprime les fichiers temporaires
    1586                          os.unlink(var_dir+os.sep+archive+'.tgz')
    1587                          os.unlink(var_dir+os.sep+archive+'.md5')
    1588                      except Exception, e:
    1589                          return 0,u("""erreur de mise en place des fichiers de la variante : %s""" % str(e))
    1590                  # l'import s'est terminé correctement
    1591                  return 1,u("ok")
    1592