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

Source Code for Module zephir.backend.dictpool

  1  # -*- coding: UTF-8 -*- 
  2  ########################################################################### 
  3  # Eole NG - 2012 
  4  # Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon) 
  5  # Licence CeCill  cf /root/LicenceEole.txt 
  6  # eole@ac-dijon.fr 
  7  # 
  8  # dictpool.py 
  9  # 
 10  # classes de gestion d'un pool de dictionnaires Creole 
 11  # avec liaison au niveau module/variante/serveur 
 12  # 
 13  ########################################################################### 
 14  """classes de gestion d'un pool de dictionnaires Creole 
 15  """ 
 16  from zephir.backend import config 
 17  from zephir.backend.config import log 
 18  from zephir.backend.lib_backend import cx_pool, PgSQL 
 19  import os, sys, time, traceback, shutil 
 20  import base64 
 21  from glob import glob 
 22   
 23  RESOURCE_TYPES = ('module', 'variante', 'serveur') 
 24   
25 -class DictPool:
26 """ 27 Classe de gestion des dictionnaires par module/variante/serveur (eole 2.3 et plus) 28 """ 29
30 - def __init__(self, eole_versions, serveur_pool):
31 """ 32 précharge une liste de dictionnaires disponibles pour 33 une version donnée de la distribution Eole 34 """ 35 self.eole_versions = eole_versions 36 self.dict_dir = {} 37 for eole_version in self.eole_versions: 38 self.dict_dir[eole_version] = os.path.join(config.ROOT_DIR, 'dictionnaires', config.DISTRIBS[int(eole_version)][1]) 39 self.serveur_pool = serveur_pool 40 self.update_data() 41 self.reset_modules()
42
43 - def update_data(self):
44 """ 45 met à jour la structure interne depuis l'aborescence 46 des dictionnaires eole/locaux 47 """ 48 self.paqs = {} 49 self.dicos = {} 50 self.variantes = {} 51 self.modules = {} 52 for eole_version in self.eole_versions: 53 self.paqs[eole_version] = {} 54 self.dicos[eole_version] = {} 55 # chargement des différents paquets et dictionnaires existants 56 for dict_type in ('eole', 'local'): 57 self.update_dicts(eole_version, dict_type) 58 # chargement de la liste des modules/variantes compatibles 59 req = """select modules.id, modules.libelle, variantes.id from variantes, modules where modules.id=variantes.module and modules.version=%s""" 60 cu = cx_pool.create() 61 cu.execute(req, (eole_version,)) 62 data = cu.fetchall() 63 cx_pool.close(cu) 64 # on ne prend en compte que les modules pour lesquels au moins 65 # un paquet est défini dans le fichier de description du module 66 mod_defaults = {} 67 for mod, label, var in data: 68 if mod not in self.modules: 69 # il faut remplir self.modules avant d'utiliser get_module_defaults 70 # l'entrée est supprimée ensuite si aucun paquet n'est défini 71 self.modules[mod] = (label, eole_version) 72 if len(self.get_module_defaults(mod)) == 0: 73 # pas de paquets déclarés, on ne gère pas ce module avec le pool 74 del(self.modules[mod]) 75 else: 76 print "Utilisation du pool de dictionnaires pour le module: %s" % label 77 vars = self.variantes.get(mod, []) 78 vars.append(var) 79 self.variantes[mod] = vars
80
81 - def update_dicts(self, eole_version, dict_type):
82 """rechargement de la représentation de l'arborescence des dictionnaires 83 dict_type : dictionnaires de type 'local' ou 'eole' 84 """ 85 self.paqs[eole_version][dict_type] = {} 86 self.dicos[eole_version][dict_type] = {} 87 dict_dir = os.path.join(self.dict_dir[eole_version], dict_type) 88 if not os.path.isdir(dict_dir): 89 os.makedirs(dict_dir) 90 paq_eole = os.listdir(dict_dir) 91 # dictionnaires gérés par des paquets 92 for paq_dir in paq_eole: 93 if os.path.isdir(os.path.join(self.dict_dir[eole_version], dict_type, paq_dir)): 94 self.paqs[eole_version][dict_type][paq_dir] = glob(os.path.join(self.dict_dir[eole_version], dict_type, paq_dir, '*.xml')) 95 # dictionnaires isolés 96 dicos = glob(os.path.join(self.dict_dir[eole_version], dict_type,'*.xml')) 97 for dict_path in dicos: 98 self.dicos[eole_version][dict_type][os.path.basename(dict_path)] = dict_path
99
100 - def get_paq_dict(self, eole_version, liste_paqs, full_path=True):
101 """renvoie une liste de dictionnaires 102 à partir d'une liste de paquets 103 """ 104 dicos_mod = [] 105 for paq in liste_paqs: 106 # on vérifie qu'on n'a pas une chaine vide (fichier sans paquet) ou une ligne commentée 107 if paq and not paq.startswith('#'): 108 type_paq, paq_name = os.path.split(paq) 109 if paq_name in self.paqs[eole_version].get(type_paq, {}): 110 if full_path: 111 dicos_mod.extend(self.paqs[eole_version][type_paq][paq_name]) 112 else: 113 dicos_mod.append(paq_name) 114 return dicos_mod
115
116 - def check_dict(self, eole_version, dict_type, dict_name):
117 """ 118 vérifie si un dictionnaire donné est bien référencé 119 """ 120 if dict_name.endswith('.xml'): 121 if dict_name not in self.dicos[eole_version][dict_type]: 122 raise ValueError, "dictionnaire non référencé : %s" % dict_name 123 elif dict_name not in self.paqs[eole_version][dict_type]: 124 raise ValueError, "paquet inconnu : %s" % dict_name
125
126 - def check_type_res(self, res_type):
127 """ 128 vérifie que le type de ressource demandée est reconnu 129 """ 130 if res_type not in RESOURCE_TYPES: 131 raise ValueError, "Type de ressource inconnu : %s" % res_type
132
133 - def check_module(self, id_module):
134 """vérifie si un numéro de module est géré par le pool 135 """ 136 return int(id_module) in self.modules
137
138 - def get_database_dict(self, eole_version, type_res, id_res, full_path=True):
139 """ récupère les dictionnaires/paquets additionnels 140 stockés en base de données 141 type_res : type de ressource (serveur, variante, module) 142 id_res : identifiant de la ressource 143 """ 144 self.check_type_res(type_res) 145 tablename = "dict_%s" % type_res 146 req = "select dict_type, dict_name from " + tablename + " where id_resource=%s""" 147 cursor = cx_pool.create() 148 try: 149 cursor.execute(req, (int(id_res),)) 150 data = cursor.fetchall() 151 except: 152 raise ValueError('%s introuvable : %s' % (type_res, id_res)) 153 cx_pool.close(cursor) 154 dicos_mod = [] 155 for dict_type, dict_name in data: 156 if full_path: 157 # renvoie le chemin complet des dictionnaires associés (+ dictionnaires des paquets) 158 if dict_name in self.paqs[eole_version][dict_type]: 159 dicos_mod.extend(self.paqs[eole_version][dict_type][dict_name]) 160 elif dict_name.endswith('.xml'): 161 dicos_mod.append(os.path.join(self.dict_dir[eole_version], dict_type, dict_name)) 162 else: 163 # on renvoie juste le nom de paquet/dictionnaire 164 dicos_mod.append(dict_name) 165 return dicos_mod
166
167 - def set_database_dict(self, eole_version, type_res, id_res, dict_type, dict_path):
168 """ 169 associe un(des) dictionnaire(s) à une ressource en base de données 170 type_res : 'module', 'variante' ou 'serveur' 171 dict_type : type de dictionnaire (eole ou local) 172 dict_path : nom du dictionnaire ou du paquet 173 """ 174 self.check_dict(eole_version, dict_type, dict_path) 175 # vérification de la présence du dictionnaire dans le pool interne 176 assert dict_path in self.dicos[eole_version][dict_type] or dict_path in self.paqs[eole_version][dict_type] 177 self.check_type_res(type_res) 178 # on détermine le type de dictionnaire en fonction du chemin de la ressource 179 tablename = "dict_%s" % type_res 180 req = "insert into " + tablename + " values (%s, %s, %s)" 181 cursor = cx_pool.create() 182 try: 183 cursor.execute(req, (int(id_res), dict_type, dict_path)) 184 cx_pool.commit(cursor) 185 except PgSQL.IntegrityError: 186 cx_pool.rollback(cursor) 187 raise ValueError('%s %s : utilise déjà %s' % (type_res, str(id_res), dict_path)) 188 except: 189 traceback.print_exc() 190 cx_pool.rollback(cursor) 191 raise ValueError('%s introuvable : %s' % (type_res, id_res))
192
193 - def del_database_dict(self, eole_version, type_res, id_res, dict_type, dict_path):
194 """ 195 supprime l'association entre un dictionnaire et une ressource de la base 196 """ 197 self.check_dict(eole_version, dict_type, dict_path) 198 self.check_type_res(type_res) 199 tablename = "dict_%s" % type_res 200 req = "delete from " + tablename + " where id_resource=%s and dict_type=%s and dict_name=%s" 201 cursor = cx_pool.create() 202 try: 203 cursor.execute(req, (int(id_res), dict_type, dict_path)) 204 cx_pool.commit(cursor) 205 except: 206 traceback.print_exc() 207 cx_pool.rollback(cursor) 208 raise ValueError('Entrée introuvable dans la table %s' % tablename)
209 210 ################################### 211 # Gestion du pool de dictionnaires 217
218 - def get_dict_resources(self, eole_version, dict_type, dict_name, get_links=False):
219 """ 220 liste toutes les associations liées à un dictionnaire particulier 221 retourne la liste des liens par type de ressource 222 get_paths : si False, renvoie la liste des ressources associées 223 si True, renvoie la liste des liens symboliques existants 224 """ 225 dict_resources = {} 226 for type_res in RESOURCE_TYPES: 227 dict_resources[type_res] = [] 228 tablename = 'dict_%s' % type_res 229 req = "select id_resource from " + tablename + " where dict_type=%s and dict_name=%s" 230 cursor = cx_pool.create() 231 try: 232 cursor.execute(req, (dict_type, dict_name)) 233 data = cursor.fetchall() 234 cx_pool.close(cursor) 235 except: 236 cx_pool.close(cursor) 237 return dict_resources 238 for id_entry in data: 239 # calcul du chemin du lien symbolique créé pour la ressource 240 id_res = id_entry[0] 241 if get_links: 242 res_links = self.get_link_path(int(eole_version), id_res, type_res, dict_type, dict_name) 243 if res_links: 244 for res_link in res_links: 245 if os.path.islink(res_link): 246 dict_resources[type_res].append(res_link) 247 else: 248 dict_resources[type_res].append(id_res) 249 return dict_resources
250 286
287 - def add_dict(self, eole_version, dict_name, content, paq_name=""):
288 """ 289 ajoute/met à jour un dictionnaire dans le pool local 290 paq_name : nom du paquet intégrant le dictionnaire ou rien si 291 le dictionnaire est isolé 292 """ 293 # création du répertoire du paquet si besoin 294 try: 295 if paq_name: 296 dict_dir = os.path.join(self.dict_dir[eole_version], 'local', paq_name) 297 else: 298 dict_dir = os.path.join(self.dict_dir[eole_version], 'local') 299 if not os.path.isdir(dict_dir): 300 os.makedirs(dict_dir) 301 # sauvegarde du contenu du dictionnaire. On l'écrase si il existe déjà 302 dict_file = open(os.path.join(dict_dir, dict_name), 'w') 303 dict_file.write(base64.decodestring(content)) 304 dict_file.close() 305 except: 306 # erreur d'écriture ? 307 traceback.print_exc() 308 return False 309 # ajout du dictionnaire/paquet dans la liste interne si tout s'est bien passé 310 self.update_dicts(eole_version, 'local') 311 return True
312
313 - def get_dict(self, eole_version, type_dict, dict_name, paq_name=""):
314 """ 315 renvoie le contenu d'un dictionnaire 316 dict_name : nom du dictionnaire à récupérer 317 paq_name : nom du paquet contenant le dictionnaire ou rien 318 """ 319 content = "" 320 if paq_name: 321 dict_path = os.path.join(self.dict_dir[eole_version], type_dict, paq_name, dict_name) 322 else: 323 dict_path = os.path.join(self.dict_dir[eole_version], type_dict, dict_name) 324 assert os.path.exists(dict_path), "Fichier non retrouvé" 325 return base64.encodestring(open(dict_path).read())
326
327 - def remove_dict(self, eole_version, dict_name, paq_name=""):
328 """ 329 supprimer un dictionnaire/paquet du pool local 330 dict_name : nom du dictionnaire / paquet à supprimer 331 paq_name : nom du paquet contenant le dictionnaire ou rien 332 """ 333 # cas possibles : 334 # 1) dictionnaire isolé / paquet : rechercher tous les liens et les supprimer 335 # 2) dictionnaire dans un paquet : supprimer seulement le dictionnaire 336 if not paq_name: 337 # récupération de tous les liens sur ce dictionnaire / paquet 338 dict_links = self.get_dict_links(eole_version, 'local', dict_name) 339 for links in dict_links.values(): 340 for dict_link in links: 341 if os.path.islink(dict_link): 342 os.unlink(dict_link) 343 else: 344 # cas 2 : obligatoirement fichier .xml 345 assert dict_name.endswith('.xml'), "fichier invalide : dictionnaire xml requis" 346 # dans tous les cas : suppression du dictionnaire 347 try: 348 dict_path = os.path.join(self.dict_dir[eole_version], 'local', paq_name, dict_name) 349 assert os.path.exists(dict_path) 350 if os.path.isdir(dict_path): 351 shutil.rmtree(dict_path) 352 else: 353 os.unlink(dict_path) 354 except: 355 return False 356 # suppression globale dans la base (cas 1) 357 if not paq_name: 358 for type_res in RESOURCE_TYPES: 359 tablename = 'dict_%s' % type_res 360 req = "delete from " + tablename + " where dict_type='local' and dict_name=%s" 361 cursor = cx_pool.create() 362 try: 363 cursor.execute(req, (dict_name,)) 364 cx_pool.commit(cursor) 365 except: 366 traceback.print_exc() 367 cx_pool.rollback(cursor) 368 return False 369 self.update_dicts(eole_version, 'local') 370 return True
371 372 ############################################# 373 # gestion des dictionnaires au niveau module 374
375 - def list_module(self, id_module, full_path=True):
376 """ 377 liste les dictionnaires/paquets associés 378 à un module dans la base de données 379 """ 380 # récupération du libellé du module 381 try: 382 libelle, module_version = self.modules[int(id_module)] 383 except: 384 raise KeyError('numéro de module inconnu ou non géré') 385 dicos_mod = self.get_module_defaults(id_module, full_path) 386 # récupération des données dans la base 387 dicos_mod.extend(self.get_database_dict(module_version, 'module', id_module, full_path)) 388 return dicos_mod
389
390 - def get_module_defaults(self, id_module, full_path=True):
391 """ 392 retourne la liste des paquets définis par défaut pour un module particulier 393 """ 394 try: 395 label, module_version = self.modules[int(id_module)] 396 except: 397 raise KeyError('numéro de module inconnu ou non géré') 398 # récupération des paquets par défaut d'un module 399 fic_module = os.path.join(config.ROOT_DIR, 'default_modules', str(module_version), label) 400 liste_paqs = open(fic_module).read() 401 liste_paqs = liste_paqs.strip().split('\n') 402 return self.get_paq_dict(module_version, liste_paqs, full_path)
403
404 - def update_module(self, id_module):
405 """ 406 met à jour la liste les liens vers les dictionnaires 407 associés à un module 408 """ 409 mod_dir = os.path.join(config.PATH_MODULES, str(id_module), 'dicos') 410 # bascule depuis l'ancien mode de gestion si le répertoire est un lien 411 if os.path.islink(mod_dir): 412 os.unlink(mod_dir) 413 if not os.path.isdir(mod_dir): 414 os.makedirs(mod_dir) 415 # lecture de la liste des dictionnaires du module 416 dicts = self.list_module(id_module) 417 # suppression et regénération de tous les liens symboliques 418 old_dicts = glob(os.path.join(mod_dir, '*.xml')) 419 for old_dict in old_dicts: 420 os.unlink(old_dict) 421 for new_dict in dicts: 422 if os.path.exists(new_dict): 423 os.symlink(new_dict, os.path.join(mod_dir, os.path.basename(new_dict)))
424
425 - def add_module_dict(self, id_module, dict_type, dict_path):
426 """ 427 ajoute un dictionnaire à un module 428 """ 429 # vérification du n° de module 430 if not int(id_module) in self.modules: 431 raise ValueError('module incompatible (distribution non gérée)') 432 module_version = self.modules[int(id_module)][1] 433 self.set_database_dict(module_version, 'module', id_module, dict_type, dict_path) 434 # mise à jour des liens 435 self.update_module(id_module)
436
437 - def del_module_dict(self, id_module, dict_type, dict_path):
438 """ 439 supprime un dictionnaire d'un module 440 """ 441 # vérification du n° de module 442 try: 443 libelle, module_version = self.modules[int(id_module)] 444 except KeyError: 445 raise ValueError('module incompatible (version non gérée : %s)' % config.DISTRIBS[module_version][1]) 446 # on supprime toutes les entrées dans la base 447 self.del_database_dict(module_version, 'module', id_module, dict_type, dict_path) 448 449 # XXX FIXME : interdire la supression dans les fichiers ? (au moins pour les modules Eole) 450 451 # module : on regarde si le dictionnaire n'est pas dans le fichier de description du module ?? 452 # récupération des paquets par défaut du module 453 fic_module = os.path.join(config.ROOT_DIR, 'default_modules', str(module_version), libelle) 454 liste_paqs = open(fic_module).read() 455 liste_paqs = liste_paqs.strip().split('\n') 456 if dict_path in liste_paqs: 457 # suppression de l'entrée dans le fichier 458 liste_paqs.remove(dict_path) 459 f_mod = open(fic_module, 'w') 460 f_mod.write('\n'.join(liste_paqs)) 461 f_mod.close() 462 self.update_module(id_module)
463 464 ############################################### 465 # gestion des dictionnaires au niveau variante 466
467 - def get_var_mod(self, id_variante):
468 """ 469 vérifie que la distribution de la variante est gérée et renvoie son n° de module 470 """ 471 id_mod = None 472 for mod, vars in self.variantes.items(): 473 if int(id_variante) in vars: 474 id_mod = mod 475 if id_mod is None: 476 raise ValueError("Variante inconnue ou incompatible (distribution non gérée)") 477 module_version = self.modules[id_mod][1] 478 return id_mod, module_version
479
480 - def check_passvar(self, id_variante, cred_user, pass_var):
481 """Vérification du mot de passe/propriétaire de la variante 482 A appeler avant add(del)_variante_dict 483 """ 484 query = "select owner, passmd5 from variantes where id=%s" 485 cursor = cx_pool.create() 486 try: 487 cursor.execute(query, (int(id_variante),)) 488 owner, passmd5 = cursor.fetchone() 489 except: 490 raise ValueError('variante introuvable : %s' % str(id_variante)) 491 cx_pool.close(cursor) 492 if owner != cred_user: 493 # vérification du mot de passe 494 if passmd5 != pass_var and passmd5 not in [None,'', BLANK_MD5]: 495 # mauvais mot de passe 496 return False 497 return True
498
499 - def list_variante(self, id_variante, full_path=True):
500 """ 501 liste les dictionnaires/paquets associés 502 à une variante dans la base de données 503 """ 504 # vérification de la version de distribution 505 id_mod, module_version = self.get_var_mod(id_variante) 506 return self.get_database_dict(module_version, 'variante', id_variante, full_path)
507
508 - def update_variante(self, id_variante, id_mod = None):
509 """ 510 met à jour la liste les liens vers les dictionnaires 511 associés à une variante 512 """ 513 if id_mod is None: 514 id_mod, module_version = self.get_var_mod(id_variante) 515 else: 516 module_version = self.modules[id_mod][1] 517 dicts = self.get_database_dict(module_version, 'variante', int(id_variante)) 518 var_dir = os.path.join(config.PATH_MODULES, str(id_mod), 'variantes', str(id_variante), 'dicos') 519 if not os.path.isdir(var_dir): 520 os.makedirs(var_dir) 521 var_paq_dir = os.path.join(config.PATH_MODULES, str(id_mod), 'variantes', str(id_variante), 'package') 522 if not os.path.isdir(var_paq_dir): 523 os.makedirs(var_paq_dir) 524 # suppression et regénération de tous les liens symboliques 525 old_dicts = glob(os.path.join(var_dir, '*.xml')) 526 old_dicts.extend(glob(os.path.join(var_paq_dir, '*.xml'))) 527 # XXX FIXME gérer les erreurs 528 for old_dict in old_dicts: 529 os.unlink(old_dict) 530 for new_dict in dicts: 531 dirname = new_dict.split(os.sep)[-2] 532 if dirname in ('eole', 'local'): 533 # on a affaire à un dictionnaire isolé 534 dest_dir = var_dir 535 else: 536 # dictionnaire de paquet, on ne l'ajoute pas local pour éviter 537 # les doublons avec ceux isntallés par le paquet 538 dest_dir = var_paq_dir 539 if not os.path.isdir(dest_dir): 540 os.makedirs(dest_dir) 541 os.symlink(new_dict, os.path.join(dest_dir, os.path.basename(new_dict))) 542 self.sync_variante_paqs(id_variante)
543
544 - def sync_variante_paqs(self, id_variante):
545 """synchronise les paquets additonnels et les paquets de dictonnaires d'une variante 546 """ 547 module, module_version = self.get_var_mod(int(id_variante)) 548 f_perso = os.path.join(config.PATH_MODULES, str(module), 'variantes', str(id_variante), 'fichiers_zephir', 'fichiers_variante') 549 variantes_files, variante_paqs = self.serveur_pool.get_fic_perso(f_perso) 550 # paquets définis en base 551 var_dicts = self.list_variante(id_variante, False) 552 # on ne garde que les paquets (pas les dictionnaires isolés) ? 553 paq_dicts = set([ paq for paq in var_dicts if not paq.endswith('.xml') ]) 554 # récupération de l'ensemble des paquets de dictionnaires connus pour 555 # la distribution de ce serveur 556 dict_paqs_eole = set(self.paqs[module_version]['eole'].keys()) 557 dict_paqs_local = set(self.paqs[module_version]['local'].keys()) 558 # recherche des paquets de dictionnaires non mis en base 559 local_paqs = dict_paqs_local.intersection(variante_paqs) 560 for paq in local_paqs: 561 if paq not in paq_dicts: 562 self.add_variante_dict(id_variante, 'local', paq) 563 eole_paqs = dict_paqs_eole.intersection(variante_paqs) 564 for paq in eole_paqs: 565 if paq not in paq_dicts: 566 self.add_variante_dict(id_variante, 'eole', paq) 567 # recherche des paquets en base non installés par la variante 568 new_paqs = [] 569 for paq in paq_dicts: 570 if paq not in variante_paqs: 571 new_paqs.append(paq) 572 if new_paqs: 573 variante_paqs.extend(new_paqs) 574 self.serveur_pool.save_fic_perso(variantes_files, variante_paqs, f_perso)
575
576 - def add_variante_dict(self, id_variante, dict_type, dict_path):
577 """ 578 ajoute un dictionnaire à un module 579 """ 580 # récupération de l'identifiant du module 581 id_mod, module_version = self.get_var_mod(id_variante) 582 self.set_database_dict(module_version, 'variante', id_variante, dict_type, dict_path) 583 # mise à jour des liens 584 self.update_variante(id_variante, id_mod)
585
586 - def del_variante_dict(self, id_variante, dict_type, dict_path):
587 """ 588 supprime un dictionnaire d'une variante 589 """ 590 # vérification du n° de module/variante 591 id_mod, module_version = self.get_var_mod(id_variante) 592 # on supprime toutes les entrées dans la base 593 self.del_database_dict(module_version, 'variante', id_variante, dict_type, dict_path) 594 # si paquet de dictionnaires supprimé, on le supprime aussi de fichiers_variante 595 f_perso = os.path.join(config.PATH_MODULES, str(id_mod), 'variantes', str(id_variante), 'fichiers_zephir', 'fichiers_variante') 596 fic_var, paq_var = self.serveur_pool.get_fic_perso(f_perso) 597 if dict_path in paq_var: 598 paq_var.remove(dict_path) 599 self.serveur_pool.save_fic_perso(fic_var, paq_var, f_perso) 600 # mise à jour des liens sur les dictionnaires du pool 601 self.update_variante(id_variante, id_mod)
602 603 ############################################## 604 # gestion des dictionnaires au niveau serveur 605
606 - def get_serveur(self, id_serveur):
607 """ 608 vérifie que la distribution du serveur est gérée et renvoie l'objet Serveur associé 609 """ 610 try: 611 serveur = self.serveur_pool[int(id_serveur)] 612 # on vérifie la version du serveur 613 assert serveur.id_mod in self.modules 614 except: 615 raise KeyError('Serveur incompatible (distribution non gérée)') 616 return serveur
617
618 - def list_serveur(self, id_serveur, full_path=True):
619 """ 620 liste les dictionnaires/paquets associés 621 à un serveur dans la base de données 622 """ 623 serveur = self.get_serveur(id_serveur) 624 return self.get_database_dict(self.modules[serveur.id_mod][1], 'serveur', serveur.id_s, full_path)
625
626 - def update_serveur(self, id_serveur):
627 """ 628 met à jour la liste les liens vers les dictionnaires 629 associés à un serveur 630 """ 631 serveur = self.get_serveur(id_serveur) 632 self.check_dirs(serveur) 633 # lecture de la liste des dictionnaires du serveur 634 dicts = self.get_database_dict(self.modules[serveur.id_mod][1], 'serveur', serveur.id_s) 635 serveur_dir = os.path.join(serveur.get_confdir(), 'dicos', 'local') 636 paq_dir = os.path.join(serveur.get_confdir(), 'dicos', 'package') 637 # suppression et regénération de tous les liens symboliques 638 old_dicts = glob(os.path.join(serveur_dir, '*.xml')) 639 old_dicts.extend(glob(os.path.join(paq_dir, '*.xml'))) 640 # XXX FIXME gérer les erreurs 641 for old_dict in old_dicts: 642 # on ne touche pas aux dictionnaires stockés 'physiquement' dans 'dicos/local' du serveur 643 if os.path.islink(old_dict): 644 os.unlink(old_dict) 645 for new_dict in dicts: 646 dirname = new_dict.split(os.sep)[-2] 647 if dirname in ('eole', 'local'): 648 # on a affaire à un dictionnaire isolé 649 dest_dir = serveur_dir 650 else: 651 # dictionnaire de paquet, on ne l'ajoute pas local pour éviter 652 # les doublons avec ceux isntallés par le paquet 653 dest_dir = paq_dir 654 if os.path.isfile(os.path.join(dest_dir, os.path.basename(new_dict))): 655 log.msg('serveur %s : lien vers %s non créé, dictionnaire local existant' % (str(id_serveur), new_dict)) 656 elif not os.path.isdir(dest_dir): 657 os.makedirs(dest_dir) 658 os.symlink(new_dict, os.path.join(dest_dir, os.path.basename(new_dict)))
659
660 - def check_dirs(self, serveur):
661 """vérifie qu'un serveur possède bien tous les liens nécessaires 662 à la gestion des dictionnaires par dictpool 663 664 serveur: objet serveur du pool de serveur Zéphir 665 666 les répertoires de dictionnaires sont : 667 local : dictionnaires particuliers au serveur 668 package : dictionnaires livrés par des paquets particulier au serveur 669 variante : dictionnaires particuliers à la variante 670 var_package : dictionnaires livrés par des paquets définis dans la variante 671 module : dictionnaires définis au niveau module (et paquets du module) 672 (pour le module, on ne fait pas de distinction pour les dictionnaire livrés 673 par des paquets, aucun de ces dictionnaires n'étant envoyés au serveur) 674 """ 675 # vérification des liens sur le module et la variante 676 mod_dir = os.path.join(config.PATH_MODULES, str(serveur.id_mod)) 677 var_dir = os.path.join(mod_dir, 'variantes', str(serveur.id_var)) 678 if not os.path.isdir(os.path.join(serveur.get_confdir(), 'dicos', 'package')): 679 os.makedirs(os.path.join(serveur.get_confdir(), 'dicos', 'package')) 680 if not os.path.islink(os.path.join(serveur.get_confdir(), 'dicos', 'module')): 681 os.symlink(os.path.join(mod_dir, 'dicos'), os.path.join(serveur.get_confdir(), 'dicos', 'module')) 682 if not os.path.islink(os.path.join(serveur.get_confdir(), 'dicos', 'variante')): 683 os.symlink(os.path.join(var_dir, 'dicos'), os.path.join(serveur.get_confdir(), 'dicos', 'variante')) 684 if not os.path.islink(os.path.join(serveur.get_confdir(), 'dicos', 'var_package')): 685 os.symlink(os.path.join(var_dir, 'package'), os.path.join(serveur.get_confdir(), 'dicos', 'var_package'))
686
687 - def sync_serveur_packages(self, id_serveur):
688 """synchronise l'état des paquets installés avec 689 les dictionnaires activés 690 """ 691 serveur = self.get_serveur(id_serveur) 692 module_version = self.modules[serveur.id_mod][1] 693 # liste des paquets de dictionnaires installés par défaut sur ce module 694 module_paqs = set(self.get_module_defaults(serveur.id_mod, False)) 695 # récupération de l'ensemble des paquets de dictionnaires connus pour 696 # la distribution de ce serveur 697 dict_paqs_eole = set(self.paqs[module_version]['eole'].keys()) 698 dict_paqs_local = set(self.paqs[module_version]['local'].keys()) 699 # vérification des paquets installés remontés par le serveur 700 pkg_file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','packages%s.list' % serveur.id_s) 701 serveur_paqs = [] 702 serveur_dicts = [] 703 new_paqs = [] 704 new_dicts = [] 705 # if not os.path.isfile(pkg_file): 706 # le serveur n'a jamais remonté sa liste de paquets 707 # on considère qu'il possède les paquets de base du module et de la variante 708 # les paquets additionnels au niveau module sont ajoutés aux paquets du serveur 709 for dict_name in self.get_database_dict(module_version, 'variante', serveur.id_var, False): 710 if not dict_name.endswith('.xml'): 711 serveur_paqs.append(dict_name) 712 serveur_paqs = set(serveur_paqs) 713 # FIXME : détection automatique des paquets déjà installés ? 714 #else: 715 # for line in open(pkg_file): 716 # serveur_paqs.append(line.split()[0]) 717 # serveur_paqs = set(serveur_paqs) 718 # # ajout des paquets installés en base si besoin 719 # for eole_paq in dict_paqs_eole.intersection(serveur_paqs): 720 # serveur_dicts.append(('eole', eole_paq)) 721 # for local_paq in dict_paqs_local.intersection(serveur_paqs): 722 # serveur_dicts.append(('local', local_paq)) 723 # log.msg('*** SYNC SERVEUR: paquets déjà installés: %s' % str(serveur_dicts)) 724 725 # si des paquets sont en attente d'installation au niveau serveur, on vérifie qu'ils sont activés 726 f_perso = os.path.join(serveur.get_confdir(), 'fichiers_zephir', 'fichiers_zephir') 727 fic_serv, paq_serv = self.serveur_pool.get_fic_perso(f_perso) 728 for dict_name in dict_paqs_eole.intersection(set(paq_serv)): 729 if dict_name not in serveur_paqs: 730 serveur_dicts.append(('eole', dict_name)) 731 for dict_name in dict_paqs_local.intersection(set(paq_serv)): 732 if dict_name not in serveur_paqs: 733 serveur_dicts.append(('local', dict_name)) 734 # liste des paquets de dictionnaires sélectionnés 735 # et ajout de paquets à installer sur le serveur si besoin 736 dict_paqs_serveur = self.get_database_dict(module_version, 'serveur', serveur.id_s, False) 737 # pas de prise en compte des paquets ajoutés au niveau module : à calculer 738 # dynamiquement au moment de l'envoi de conf au serveur ? 739 # dict_paqs_serveur.extend(self.get_database_dict(module_version, 'module', serveur.id_mod,False)) 740 dict_paqs_serveur = set([paq for paq in dict_paqs_serveur if not paq.endswith('.xml')]) 741 # recherche des paquets référencés en base pour le serveur et non déclarés dans fichiers_zephir 742 for eole_paq in dict_paqs_serveur.difference(serveur_paqs): 743 new_paqs.append(eole_paq) 744 # ajout des nouvelles entrées en base si besoin 745 for dict_type, dict_path in serveur_dicts: 746 # les paquets de base du module sont ignorés 747 if dict_path not in dict_paqs_serveur and dict_path not in module_paqs: 748 self.add_serveur_dict(serveur.id_s, dict_type, dict_path, False) 749 new_dicts.append(dict_path) 750 # mise à jour des liens vers les dictionnaires 751 self.update_serveur(id_serveur) 752 # ajout de paquets supplémentaires à installer sur le serveur 753 added_paqs = serveur.add_packages(new_paqs) 754 return added_paqs, new_dicts
755
756 - def add_serveur_dict(self, id_serveur, dict_type, dict_path, update=True):
757 """ 758 ajoute un dictionnaire à un module 759 update: pas de mise à jour des liens du serveur si False 760 (à utiliser pour les traitements par lot) 761 """ 762 serveur = self.get_serveur(id_serveur) 763 module_version = self.modules[serveur.id_mod][1] 764 self.set_database_dict(module_version, 'serveur', serveur.id_s, dict_type, dict_path) 765 if update: 766 # mise à jour des liens 767 self.sync_serveur_packages(id_serveur)
768
769 - def del_serveur_dict(self, id_serveur, dict_type, dict_path, update=True):
770 """ 771 supprime un dictionnaire d'un serveur 772 update: pas de mise à jour des liens du serveur si False 773 (à utiliser pour les traitements par lot) 774 """ 775 serveur = self.get_serveur(id_serveur) 776 module_version = self.modules[serveur.id_mod][1] 777 # on ne gère que les dictionnaires du pool (les dictionnaires stockés 778 # au niveau serveur sont gérés indépendamment) 779 # on supprime toutes les entrées dans la base 780 self.del_database_dict(module_version, 'serveur', id_serveur, dict_type, dict_path) 781 # si paquet de dictionnaires supprimé, on le supprime aussi de fichiers_du serveur 782 f_perso = os.path.join(serveur.get_confdir(), 'fichiers_zephir', 'fichiers_zephir') 783 fic_serv, paq_serv = self.serveur_pool.get_fic_perso(f_perso) 784 if dict_path in paq_serv: 785 paq_serv.remove(dict_path) 786 self.serveur_pool.save_fic_perso(fic_serv, paq_serv, f_perso) 787 if update: 788 # mise à jour des liens sur les dictionnaires du pool 789 self.sync_serveur_packages(id_serveur)
790
791 - def list_local_serveur(self, id_serveur):
792 """ 793 Renvoie la liste des dictionnaire à envoyer et des paquets à installer pour un serveur 794 """ 795 serveur = self.get_serveur(id_serveur) 796 module_version = self.modules[serveur.id_mod][1] 797 local_serv = {'dicos':[], 'paquets':[]} 798 for type_res, id_res in (('module',serveur.id_mod), ('variante',serveur.id_var), ('serveur',serveur.id_s)): 799 # création de la liste des dictionnaires 'isolés' 800 for dict_res in self.get_database_dict(module_version, type_res, id_res): 801 if dict_res.split(os.sep)[-2] in ('local', 'eole'): 802 # dictionnaire isolé : à envoyer au serveur 803 local_serv['dicos'].append(dict_res) 804 else: 805 paq_name = dict_res.split(os.sep)[-2] 806 if paq_name not in local_serv['paquets']: 807 local_serv['paquets'].append(paq_name) 808 # ajout des autres dictionnaires stockés dans le répertoire 'dicos' du serveur 809 for dict_serveur in glob(os.path.join(serveur.get_confdir(), 'dicos', 'local' ,'*.xml')): 810 if not os.path.islink(dict_serveur): 811 local_serv['dicos'].append(dict_serveur) 812 return local_serv
813 814 #################################### 815 # fonctions utilitaires pour Zéphir 816
817 - def reset_modules(self):
818 """ 819 met à jour les liens des dictionnaires pour l'ensemble des modules/variantes gérés 820 """ 821 for id_mod, variantes in self.variantes.items(): 822 if id_mod in self.modules: 823 log.msg("Réinitialisation des dictionnaires de module / variantes : %s" % self.modules[id_mod][0]) 824 self.update_module(id_mod) 825 for id_var in variantes: 826 self.update_variante(id_var)
827
828 -def init_dictpool(serveur_pool):
829 """ 830 fonction d'initialisation du pool de dictionnaire 831 """ 832 # détection des version de distribution disponibles dans le pool 833 versions = [] 834 for eole_version in config.DISTRIBS: 835 # on ne regarde que les version supérieures à eole 2.3 836 if eole_version >= 5: 837 dict_path = os.path.join(config.ROOT_DIR, 'dictionnaires', config.DISTRIBS[int(eole_version)][1]) 838 if os.path.isdir(os.path.join(dict_path, 'eole')): 839 # répertoire de paquets présents, on gère les dictionnaires de cette distribution 840 # on ajoute le répertoire 'local' si il n'existe pas 841 if not os.path.isdir(os.path.join(dict_path, 'local')): 842 os.makedirs(os.path.join(dict_path, 'local')) 843 versions.append(eole_version) 844 return DictPool(versions, serveur_pool)
845