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

Source Code for Module zephir.backend.lib_backend

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