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

Source Code for Module zephir.backend.uucp_rpc

   1  # -*- coding: UTF-8 -*- 
   2  ########################################################################### 
   3  # Eole NG - 2007   
   4  # Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon) 
   5  # Licence CeCill  cf /root/LicenceEole.txt 
   6  # eole@ac-dijon.fr  
   7  #   
   8  # uucp_rpc.py 
   9  #   
  10  # fonctions xmlrpc pour la gestion des actions sur les serveurs dans Zephir 
  11  #        
  12  ########################################################################### 
  13  """Module gérant les actions sur les serveurs (via uucp) 
  14  """ 
  15  from zephir.backend.db_utils import * 
  16  from zephir.backend.uucp_utils import uucp_pool, UUCPError, COMMANDS 
  17  from zephir.backend import config 
  18  from zephir.backend.config import u, log 
  19  from zephir.backend.xmlrpceole import XMLRPCEole as XMLRPC 
  20  from zephir.monitor.collecteur import AgentCollecteur, ServeurStatus 
  21  from zephir.lib_zephir import save_modes 
  22  from twisted.internet import defer, reactor 
  23   
  24  import sys,os,shutil,time,smtplib,re,time,base64,glob,email 
  25  from email.header import Header 
  26  from datetime import datetime 
  27  import traceback 
  28  import psycopg2 as PgSQL 
  29  from cStringIO import StringIO 
  30   
31 -class RPCUucp(XMLRPC):
32 """serveur XMLRPC zephir pour la gestion des actions sur les serveurs 33 """ 34
35 - def __init__(self,parent,agent_manager):
36 self.dbpool = db_connect() 37 self.dbpool.noisy = 0 38 XMLRPC.__init__(self) 39 self.agent_manager = agent_manager 40 self.parent=parent 41 # booléen pour empêcher le lancement de plusieurs boucles 42 # de vérification des timeouts 43 self.scan_delay = config.SCAN_DELAY 44 # au lancement, on modifie la date de dernier contact 45 # des serveurs pour éviter des alertes injustifiées 46 self.start_time = str(time.time())
47
48 - def _send_files(self,serv,archive,files,uucp=0):
49 """met en queue des fichiers ou répertoires pour un serveur distant 50 et stocke la somme md5 des fichiers envoyés dans le fichier cheksum.txt du 51 systeme en question (dans zephir/conf/rne/serveur/)""" 52 # définition du nodename uucp du système 53 id_uucp = str(serv.get_rne())+'-'+str(serv.id_s) 54 # chemin vers les fichiers du serveur sur zephir 55 serveur_dir = serv.get_confdir() 56 cmd_tar = ['cd ',serveur_dir,';','/bin/tar','--same-owner','-chpf',archive+'.tar'] 57 # création du fichier tar à envoyer 58 for fic in files: 59 # on vérifie l'existence du fichier 60 if os.path.exists(os.path.join(serveur_dir,fic)): 61 cmd_tar.append(fic) 62 else: 63 # cas spécial : lien sur dico.eol, zephir.eol, droits_zephir et droits_variante (si conf pas encore saisie) 64 if fic not in ['dico.eol','zephir.eol', 'droits_variante', 'droits_zephir']: 65 # un fichier n'est pas trouvé, on annule 66 return 0, u("""fichier %s introuvable""" % os.path.join(serveur_dir,fic) ) 67 cmd_tar.append('>/dev/null 2>&1') 68 res=os.system(" ".join(cmd_tar)) 69 if res != 0: 70 return 0, u("""erreur de creation de l'archive %s.tar dans %s""" % (archive,serveur_dir)) 71 # calcul et stockage d'un checksum md5 de l'archive 72 cmd_checksum = """cd %s ;md5sum -b %s.tar > %s.md5""" % (serveur_dir,archive,archive) 73 os.system(cmd_checksum) 74 if uucp: 75 # envoi de l'archive par uucp si demandé 76 try: 77 res = uucp_pool.add_file(id_uucp,os.path.join(serveur_dir,archive+".tar")) 78 except UUCPError,e: 79 return 0, u("Erreur UUCP %s" % str(e)) 80 return 1,u(archive+'.tar')
81
82 - def xmlrpc_reconfigure(self,cred_user,id_serveur):
83 """prépare la reconfiguration d'un serveur""" 84 try: 85 id_serveur = int(id_serveur) 86 serv = self.parent.s_pool.get(cred_user,id_serveur) 87 except (KeyError, ValueError): 88 return 0,u("serveur inconnnu dans la base zephir") 89 else: 90 id_uucp = str(serv.get_rne())+'-'+str(id_serveur) 91 try: 92 res = uucp_pool.add_cmd(id_uucp,"zephir_client reconfigure") 93 except UUCPError,e: 94 return 0, u("Erreur UUCP %s" % str(e)) 95 return 1, u('ok')
96
97 - def xmlrpc_service_restart_groupe(self,cred_user,liste,service):
98 """prépare le redémarrage d'un service sur un groupe""" 99 erreurs=[] 100 for serveur in liste: 101 retour = self.xmlrpc_service_restart(cred_user, serveur['id'], service) 102 if retour[0] == 0: 103 erreurs.append(str(serveur['id'])+' : '+retour[1]) 104 if erreurs != []: 105 return 0,u(erreurs) 106 else: 107 return 1, u('ok')
108
109 - def xmlrpc_service_restart(self,cred_user,id_serveur,service):
110 """exécution de la commande uucp pour redémarrer un service""" 111 try: 112 id_serveur = int(id_serveur) 113 serv = self.parent.s_pool.get(cred_user, id_serveur) 114 except (KeyError, ValueError): 115 return 0,u("serveur inconnnu dans la base zephir") 116 else: 117 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 118 # appel uucp 119 try: 120 uucp_pool.add_cmd(id_uucp,"zephir_client service_restart %s" % service) 121 except UUCPError,e: 122 return 0, u("erreur uucp (%s)" % str(e)) 123 return 1,u("ok")
124
125 - def xmlrpc_reboot_groupe(self,cred_user,liste):
126 """prépare le redémarrage d'un groupe de serveurs""" 127 erreurs=[] 128 for serveur in liste: 129 retour = self.xmlrpc_reboot(cred_user, serveur['id']) 130 if retour[0] == 0: 131 erreurs.append(str(serveur['id'])+' : '+retour[1]) 132 if erreurs != []: 133 return 0,u(erreurs) 134 else: 135 return 1, u('ok')
136
137 - def xmlrpc_reboot(self,cred_user,id_serveur):
138 """exécution de la commande uucp pour redémarrer un serveur""" 139 try: 140 id_serveur = int(id_serveur) 141 serv = self.parent.s_pool.get(cred_user, id_serveur) 142 except (KeyError, ValueError): 143 return 0,u("serveur inconnnu dans la base zephir") 144 else: 145 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 146 # appel uucp 147 try: 148 uucp_pool.add_cmd(id_uucp,"zephir_client reboot") 149 except UUCPError,e: 150 return 0, u("serveur %s : erreur uucp (%s)" % (str(id_serveur), str(e))) 151 return 1,u("ok")
152 153
154 - def xmlrpc_configure(self,cred_user,id_serveur,restart=0,content=0):
155 """prépare la configuration automatique d'un serveur 156 (envoi des fichiers de configuration)""" 157 158 return self._configure(id_serveur, restart, cred_user, content)
159
160 - def xmlrpc_configure_groupe(self,cred_user,liste,restart=0,content=0):
161 """prépare la configuration automatique d'un groupe de serveurs 162 (envoi des fichiers de configuration)""" 163 erreurs = [] 164 old_clients = [] 165 for serveur in liste: 166 retour = self._configure(serveur['id'], restart, cred_user, content) 167 if retour[0] == 0: 168 erreurs.append(str(serveur['id'])+' : '+retour[1]) 169 else: 170 old_clients.extend(retour[1]) 171 if erreurs != []: 172 return 0, u(erreurs) 173 else: 174 return 1, u(old_clients)
175
176 - def _configure(self, id_serveur,restart,cred_user,content):
177 """envoie les fichiers de configuration et demande un configure-zephir""" 178 try: 179 id_serveur = int(id_serveur) 180 serv = self.parent.s_pool.get(cred_user, id_serveur) 181 except (KeyError, ValueError): 182 return 0,u("serveur inconnnu dans la base zephir") 183 query = """select users.cle from users,serveur_auth where users.login=serveur_auth.login and serveur_auth.id_serveur=%s""" 184 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD) 185 cursor=cx.cursor() 186 cursor.execute(query, (int(id_serveur),)) 187 data=cursor.fetchall() 188 cursor.close() 189 cx.close() 190 id_uucp = str(serv.get_rne())+'-'+str(id_serveur) 191 # définition du répertoire du serveur 192 serveur_dir = serv.get_confdir() 193 # définition des fichiers à transférer 194 try: 195 cles = "" 196 # on prépare le fichier des clefs ssh à transférer 197 for cle in data: 198 if cle[0]: 199 cles += base64.decodestring(cle[0]) + "\n" 200 cles.strip() 201 fic_cle = open(serveur_dir+os.sep+'auth_keys','w') 202 fic_cle.writelines(base64.encodestring(cles)) 203 fic_cle.close() 204 except: 205 return 0, u("erreur de création du fichier des cles de connexion ssh") 206 old_clients = [] 207 # si le client présent sur le serveur n'est pas assez récent, on fait une sauvegarde complète 208 files = ['dicos','patchs','fichiers_perso','fichiers_zephir','zephir.eol','dico.eol','auth_keys','droits_zephir', 'droits_variante'] 209 if serv.version == 'creole2' and serv.check_min_version('zephir-client', '2.2-eole97'): 210 # envoi partiel 211 if content not in config.data_files: 212 return 0, u("le type de données à envoyer est invalide") 213 files = config.data_files[content][1] 214 else: 215 # client trop ancien : envoi de toutes les données 216 old_clients = [id_serveur] 217 # appel de la fonction d'envoi et de calcul des md5 218 code, message = self._send_files(serv,'config-zephir',files,uucp=1) 219 try: 220 os.unlink('auth_keys') 221 except: 222 pass 223 if code == 0: 224 return code, u(message) 225 else: 226 # les fichiers sont prêts à l'envoi, on demande un 227 # configure sur le serveur distant 228 try: 229 res = uucp_pool.add_cmd(id_uucp,"zephir_client configure") 230 except UUCPError, e: 231 return 0, u("Erreur uucp : %s" % str(e)) 232 if restart == 1: 233 # on demande un reconfigure 234 code, data = self.xmlrpc_reconfigure(cred_user, id_serveur) 235 if code == 1: 236 return 1, u(old_clients) 237 else: 238 return code, data 239 else: 240 return 1, u(old_clients)
241
242 - def xmlrpc_save_conf(self,cred_user,id_serveur,mode=0):
243 """prépare la sauvegarde de configuration d'un serveur""" 244 # on vérifie l'existence du serveur dans la base 245 return self._save_conf(cred_user, id_serveur, mode)
246
247 - def xmlrpc_save_conf_groupe(self,cred_user,liste,mode=0):
248 """prépare la sauvegarde de configuration d'un serveur""" 249 erreurs=[] 250 old_clients = [] 251 for serveur in liste: 252 retour = self._save_conf(cred_user, serveur['id'], mode) 253 if retour[0] == 0: 254 erreurs.append(str(serveur['id'])+' : '+retour[1]) 255 else: 256 old_clients.extend(retour[1]) 257 if erreurs != []: 258 return 0,u(erreurs) 259 else: 260 return 1, u(old_clients)
261
262 - def _save_conf(self,cred_user,id_serveur,mode):
263 """exécution de la commande uucp pour la mise à jour""" 264 try: 265 id_serveur = int(id_serveur) 266 serv = self.parent.s_pool.get(cred_user, id_serveur) 267 except (KeyError, ValueError): 268 return 0,u("serveur inconnnu dans la base zephir") 269 else: 270 old_clients = [] 271 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 272 # appel uucp 273 # vérification du mode demandé 274 cmd_mode = "" 275 if serv.version == 'creole2' and mode in save_modes: 276 # pour éviter les problèmes avec d'anciens clients, on ne passe pas 277 # le mode si le client n'est pas assez récent 278 if serv.check_min_version('zephir-client', '2.2-eole97'): 279 cmd_mode = " %s" % str(mode) 280 else: 281 old_clients.append(id_serveur) 282 try: 283 uucp_pool.add_cmd(id_uucp,"zephir_client save_files%s" % cmd_mode) 284 except UUCPError,e: 285 return 0, u("erreur uucp (%s)" % str(e)) 286 return 1, (old_clients)
287
288 - def xmlrpc_maj(self,cred_user,id_serveur,reconf = 0, delay = "", options = ""):
289 """prépare la mise à jour d'un serveur Eole par l'intermédiare d'uucp""" 290 # on vérifie l'existence du serveur dans la base 291 if delay > 0: 292 # mise à jour différée : reconfigure est géré par la mise à jour ead 293 reconf = 0 294 return self._maj(cred_user, id_serveur, reconf, delay, options)
295
296 - def xmlrpc_maj_groupe(self,cred_user,liste,reconf = 0, delay = "", options = ""):
297 """prépare la mise à jour d'un groupe de serveurs Eole par l'intermédiare d'uucp""" 298 erreurs=[] 299 for serveur in liste: 300 retour = self._maj(cred_user, serveur['id'],reconf,delay,options) 301 if retour[0] == 0: 302 erreurs.append("serveur "+str(serveur['id'])+' : '+retour[1]) 303 if erreurs != []: 304 return 0,u(erreurs) 305 else: 306 return 1, u('ok')
307
308 - def _maj(self, cred_user, id_serveur, reconf, delay,options):
309 """exécution de la commande uucp pour la mise à jour""" 310 try: 311 id_serveur = int(id_serveur) 312 serv = self.parent.s_pool.get(cred_user,id_serveur) 313 except (KeyError, ValueError): 314 return 0,u("serveur inconnnu dans la base zephir") 315 else: 316 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 317 # construction de la commande 318 try: 319 assert int(delay) > 0 320 # si delai, on ne lance pas reconfigure par une action (lancé par la maj différée) 321 reconf = 0 322 except: 323 delay = "" 324 try: 325 if serv.version == 'creole1': 326 uucp_pool.add_cmd(id_uucp,"zephir_client maj_auto %s" % (str(delay))) 327 else: 328 uucp_pool.add_cmd(id_uucp,"zephir_client maj_auto %s %s" % (str(delay), options)) 329 except UUCPError, e: 330 return 0, u("Erreur UUCP (%s)" % str(e)) 331 # si cela est demandé, on reconfigure le serveur 332 # query = """insert into log_serveur (id_serveur,date,type,message,etat) values (%s,'%s','%s','Mise a jour',0)""" % (int(id_serveur),str(time.ctime()),'COMMAND') 333 # self.dbpool.runOperation(query) 334 if reconf == 1: 335 return self.xmlrpc_reconfigure(cred_user, id_serveur) 336 else: 337 return 1, u("ok")
338
339 - def xmlrpc_maj_client(self,cred_user,id_serveur):
340 """prépare la mise à jour de zephir-client sur un serveur""" 341 # on vérifie l'existence du serveur dans la base 342 return self._maj_client(cred_user, id_serveur)
343
344 - def xmlrpc_maj_client_groupe(self,cred_user,liste):
345 """prépare la mise à jour de zephir-client sur un groupe de serveurs""" 346 erreurs=[] 347 for serveur in liste: 348 retour = self._maj_client(cred_user, serveur['id']) 349 if retour[0] == 0: 350 erreurs.append("serveur "+str(serveur['id'])+' : '+retour[1]) 351 if erreurs != []: 352 return 0, u(erreurs) 353 else: 354 return 1, u('ok')
355
356 - def _maj_client(self,cred_user,id_serveur):
357 """exécution de la commande uucp pour la mise à jour de zephir-client""" 358 try: 359 id_serveur = int(id_serveur) 360 serv = self.parent.s_pool.get(cred_user,id_serveur) 361 except (KeyError, ValueError): 362 return 0,u("serveur inconnnu dans la base zephir") 363 else: 364 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 365 # construction de la commande 366 try: 367 uucp_pool.add_cmd(id_uucp,"zephir_client maj_client") 368 except UUCPError, e: 369 return 0, u("Erreur UUCP (%s)" % str(e)) 370 else: 371 return 1, u("ok")
372
373 - def xmlrpc_sphynx_add(self,cred_user,id_sphynx,id_amon,content):
374 """stocke la configuration RVP d'un amon vers ce sphynx""" 375 try: 376 id_sphynx = int(id_sphynx) 377 id_amon = int(id_amon) 378 sphynx = self.parent.s_pool.get(cred_user,id_sphynx) 379 amon = self.parent.s_pool.get(cred_user,id_amon) 380 except (KeyError, ValueError): 381 return 0,u("serveur inconnnu dans la base zephir") 382 # on vérifie l'existence d'amon 383 if not amon.get_module().startswith('amon'): 384 return 0, "serveur invalide : %s" % str(id_amon) 385 # on regarde si ce tunnel existe déjà 386 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD) 387 cursor=cx.cursor() 388 query = """select id_amon from conf_vpn where id_sphynx=%s""" 389 cursor.execute(query, (int(id_sphynx),)) 390 data=cursor.fetchall() 391 cursor.close() 392 cx.close() 393 # chemin de sauvegarde de l'archive contenant la conf RVP 394 sphynx_dir = sphynx.get_confdir() 395 if not os.path.exists(sphynx_dir + os.sep + 'vpn'): 396 os.makedirs(sphynx_dir + os.sep + 'vpn') 397 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz' 398 # mise à jour de la table des tunnels configurés 399 confs = [ligne[0] for ligne in data] 400 if int(id_amon) in confs: 401 # on a déjà une conf vpn pour cet amon, mise à jour 402 query = """update conf_vpn set etat=%s where id_sphynx=%s and id_amon=%s""" 403 params = (0, int(id_sphynx), int(id_amon)) 404 else: 405 # sinon, insertion 406 query = """insert into conf_vpn (id_sphynx,id_amon,etat) values (%s,%s,%s)""" 407 params = (int(id_sphynx), int(id_amon), 0) 408 return self.dbpool.runOperation(query, params).addCallbacks(self._sphynx_add,db_client_failed,callbackArgs=[archive,content])
409
410 - def _sphynx_add(self,result,archive,content):
411 """écriture de la conf RVP""" 412 try: 413 file = StringIO() 414 data = base64.decodestring(content) 415 fd = open(archive,'wb') 416 # sauvegarde du fichier 417 file.write(data) 418 file.seek(0) 419 fd.write(file.read()) 420 fd.close() 421 except: 422 return 0, u("erreur de sauvegarde de l'archive") 423 return 1, "OK"
424
425 - def xmlrpc_sphynx_del(self,cred_user,id_sphynx,id_amon,del_row=0):
426 """supprime la configuration RVP d'un amon vers ce sphynx""" 427 try: 428 id_sphynx = int(id_sphynx) 429 id_amon = int(id_amon) 430 sphynx = self.parent.s_pool.get(cred_user,id_sphynx) 431 amon = self.parent.s_pool.get(cred_user,id_amon) 432 except (KeyError, ValueError): 433 return 0,u("serveur inconnnu dans la base zephir") 434 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD) 435 cursor=cx.cursor() 436 query = """select etat from conf_vpn where id_sphynx=%s and id_amon=%s""" 437 params = (int(id_sphynx), int(id_amon)) 438 cursor.execute(query, params) 439 data=cursor.fetchone() 440 etat = data[0] 441 cursor.close() 442 cx.close() 443 try: 444 # chemin de l'archive contenant la conf RVP 445 sphynx_dir = sphynx.get_confdir() 446 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz' 447 os.unlink(archive) 448 except: 449 if del_row == 0: 450 return 0, u("fichier de configuration RVP non supprimé (ou inexistant)") 451 if del_row == 1: 452 query = """delete from conf_vpn where id_sphynx=%s and id_amon=%s""" 453 params = (int(id_sphynx), int(id_amon)) 454 else: 455 nouv_etat=2 456 # si l'archive n'a pas été récupérée : anomalie 457 if int(etat) == 0: 458 nouv_etat=3 459 query = """update conf_vpn set etat=%s where id_sphynx=%s and id_amon=%s""" 460 params = (int(nouv_etat), int(id_sphynx), int(id_amon)) 461 return self.dbpool.runOperation(query, params).addCallbacks(lambda x : [1,u("OK")],db_client_failed)
462
463 - def xmlrpc_sphynx_get(self,cred_user,id_sphynx,id_amon):
464 """envoie la configuration RVP d'un amon vers ce sphynx""" 465 try: 466 id_sphynx = int(id_sphynx) 467 id_amon = int(id_amon) 468 sphynx = self.parent.s_pool.get(cred_user,id_sphynx) 469 amon = self.parent.s_pool.get(cred_user,id_amon) 470 except (KeyError, ValueError): 471 return 0,u("serveur inconnnu dans la base zephir") 472 try: 473 # chemin de l'archive contenant la conf RVP 474 sphynx_dir = sphynx.get_confdir() 475 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz' 476 file_conf=open(archive) 477 content=base64.encodestring(file_conf.read()) 478 file_conf.close() 479 except: 480 return 0, u("fichier de configuration RVP non trouvé") 481 query = """update conf_vpn set etat=1 where id_sphynx=%s and id_amon=%s""" 482 params = (int(id_sphynx), int(id_amon)) 483 return self.dbpool.runOperation(query, params).addCallbacks(lambda x : [1,content],db_client_failed)
484
485 - def xmlrpc_sphynx_list(self,cred_user,id_sphynx):
486 """liste les configs RVP amon présentes pour un sphynx""" 487 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD) 488 cursor=cx.cursor() 489 query = """select id_amon,etat from conf_vpn where id_sphynx=%s order by etat,id_amon desc""" % id_sphynx 490 cursor.execute(query, (int(id_sphynx),)) 491 data=cursor.fetchall() 492 cursor.close() 493 cx.close() 494 # on retourne l'id amon et son état 495 liste_amons=[] 496 for ligne in data: 497 liste_amons.append([int(ligne[0]),int(ligne[1])]) 498 return 1,liste_amons
499
500 - def xmlrpc_add_replication(self, cred_user, id_serv, id_client, content):
501 """ajoute un fichier de configuration pour réplication d'un annuaire sur seshat (ou autre)""" 502 try: 503 id_serv = int(id_serv) 504 id_client = int(id_client) 505 serv = self.parent.s_pool.get(cred_user,id_serv) 506 client = self.parent.s_pool.get(cred_user,id_client) 507 except (KeyError, ValueError): 508 return 0,u("serveur inconnnu dans la base zephir") 509 try: 510 rne = client.get_config().get_value('numero_etab')[0] 511 assert rne != "" 512 except: 513 # si pas défini dans la configuration, on prend le rne 514 # de l'établissement du serveur dans la base zephir 515 rne = client.rne 516 code, message = serv.add_replication(rne, content) 517 if code == 0: 518 return code, message 519 else: 520 # configuration ajoutée, on demande automatiquement 521 # une prise en compte sur le serveur de réplication 522 return self._update_replication(serv)
523
524 - def xmlrpc_del_replication(self, cred_user, id_serv, conf_file):
525 """supprime un fichier de configuration de réplication""" 526 try: 527 id_serv = int(id_serv) 528 serv = self.parent.s_pool.get(cred_user,id_serv) 529 except (KeyError, ValueError): 530 return 0,u("serveur inconnnu dans la base zephir") 531 return serv.del_replication(conf_file)
532
533 - def xmlrpc_update_replication(self, cred_user, id_serveur):
534 """prépare l'envoi des configurations de réplication à un serveur central, 535 et demande une regénération de la configuration 536 """ 537 try: 538 id_serveur = int(id_serveur) 539 serv = self.parent.s_pool.get(cred_user,id_serveur) 540 except (KeyError, ValueError): 541 return 0,u("serveur inconnnu dans la base zephir") 542 return self._update_replication(serv)
543
544 - def _update_replication(self, serv):
545 # définition du répertoire du serveur 546 id_uucp = '%s-%s' % (str(serv.get_rne()), str(serv.id_s)) 547 code, message = self._send_files(serv, 'replication', ['replication'], uucp=1) 548 if code == 0: 549 return code, u(message) 550 else: 551 # les fichiers sont prêts à l'envoi, on demande la prise en compte sur le serveur seshat 552 try: 553 res = uucp_pool.add_cmd(id_uucp, "zephir_client update_replication") 554 except UUCPError, e: 555 return 0, u("Erreur uucp : %s" % str(e)) 556 if os.path.isfile(os.path.join(serv.get_confdir(), 'replication', '.modified')): 557 os.unlink(os.path.join(serv.get_confdir(), 'replication', '.modified')) 558 return 1, "OK"
559
560 - def xmlrpc_check_replication(self, cred_user, id_serveur):
561 """renvoie l'état de la configuration de réplication LDAP 562 0 : pas de réplication gérée sur ce serveur 563 1 : configurations de réplication en place 564 2 : la configuration doit être renvoyée au serveur (si suppression manuelle de fichiers) 565 """ 566 try: 567 id_serveur = int(id_serveur) 568 serv = self.parent.s_pool.get(cred_user,id_serveur) 569 except (KeyError, ValueError): 570 return 0,u("serveur inconnnu dans la base zephir") 571 return serv.check_replication()
572
573 - def xmlrpc_get_replication(self, cred_user, id_serveur):
574 """renvoie la liste des configurations de réplication présentes sur un serveur 575 """ 576 try: 577 id_serveur = int(id_serveur) 578 serv = self.parent.s_pool.get(cred_user,id_serveur) 579 except (KeyError, ValueError): 580 return 0,u("serveur inconnnu dans la base zephir") 581 return serv.get_replication()
582
583 - def xmlrpc_confirm_transfer(self,cred_user,id_serveur,archive):
584 """confirme la réception d'une archive par un serveur""" 585 try: 586 id_serveur = int(id_serveur) 587 serv = self.parent.s_pool.get(cred_user,id_serveur) 588 except (KeyError, ValueError): 589 return 0,u("serveur inconnnu dans la base zephir") 590 # définition du répertoire du serveur 591 serveur_dir = serv.get_confdir() 592 try: 593 # suppression de l'archive 594 os.unlink(serveur_dir+os.sep+archive+'.tar') 595 # supression du fichier de checksum 596 os.unlink(serveur_dir+os.sep+archive+'.md5') 597 except: 598 return 0, u("""erreur de suppression de l'archive""") 599 else: 600 return 1, u('ok')
601
602 - def xmlrpc_get_checksum(self,cred_user,id_serveur,archive):
603 """confirme la réception d'une archive par un serveur""" 604 try: 605 id_serveur = int(id_serveur) 606 serv = self.parent.s_pool.get(cred_user,id_serveur) 607 except (KeyError, ValueError): 608 return 0,u("serveur inconnnu dans la base zephir") 609 # définition du répertoire du serveur 610 serveur_dir = serv.get_confdir() 611 # lecture du fichier md5 612 try: 613 fic_md5=open(serveur_dir+os.sep+archive+'.md5') 614 md5sum = fic_md5.readlines() 615 fic_md5.close() 616 except: 617 return 0, u("""fichier %s.md5 non trouve""" % (archive)) 618 else: 619 # ok, on renvoie la chaine de contrôle 620 return 1, base64.encodestring(md5sum[0])
621
622 - def xmlrpc_install_module(self,cred_user,id_module,dico_b64):
623 """installation d'un module (récupération d'un dictionnaire)""" 624 # pour l'instant, cette procédure sert à créer ou 625 # mettre à jour le dictionnaire principal du module 626 # on récupère le libellé du module dans la base 627 query = """select id, libelle, version from modules where id=%s""" % id_module 628 return self.dbpool.runQuery(query, (int(id_module),)).addCallbacks(self._install_module,db_client_failed,callbackArgs=[dico_b64])
629
630 - def _install_module(self,data,dico_b64):
631 if data == []: 632 return 0,u("""erreur, module non trouvé""") 633 else: 634 id_module = data[0][0] 635 libelle = data[0][1] 636 version = data[0][2] 637 if version == 1: 638 #creole 1 639 dico_path = os.path.abspath(config.ROOT_DIR)+os.sep+'dictionnaires' 640 dico_b64 = {'dico-'+str(libelle):dico_b64} 641 else: 642 #creole 2 643 dico_path = os.path.abspath(config.ROOT_DIR)+os.sep+'dictionnaires'+os.sep+str(libelle) 644 if not os.path.isdir(dico_path): 645 # module supplémentaire non géré par eole 646 dico_path = os.path.join(os.path.abspath(config.PATH_MODULES),str(id_module),"dicos") 647 # traitement des dictionnaires définis 648 for dic_name, data in dico_b64.items(): 649 dico = os.path.join(dico_path, dic_name) 650 try: 651 if os.path.isfile(dico): 652 # le dictionnaire existe déjà 653 os.unlink(dico) 654 # recréation du fichier avec les données transmises 655 fic_dico = open(dico,'w') 656 fic_dico.write(base64.decodestring(data)) 657 fic_dico.close() 658 except: 659 traceback.print_exc() 660 return 0,u("erreur de mise a jour du dictionnaire du module") 661 662 return 1,u("ok")
663
664 - def xmlrpc_exec_script(self, cred_user, serveurs, script_name, params):
665 """exécution d'un script client sur un serveur/groupe 666 serveurs: id du serveur ou liste d'id 667 script_name: nom du script à exécuter 668 params:paramètres supplémentaires à donner au script 669 """ 670 if type(serveurs) != list: 671 serveurs = [serveurs] 672 erreurs = [] 673 for id_serveur in serveurs: 674 try: 675 id_serveur = int(id_serveur) 676 serv = self.parent.s_pool.get(cred_user, id_serveur) 677 except: 678 erreurs.append("Serveur %s : inexistant ou accès refusé" % str(id_serveur)) 679 continue 680 try: 681 id_uucp = str(serv.get_rne()) + '-' + str(serv.id_s) 682 cmd = "zephir_client %s %s" % (script_name, params) 683 uucp_pool.add_cmd(id_uucp,cmd.strip()) 684 except UUCPError,e: 685 erreurs.append("serveur %s (%s) : Erreur UUCP %s" % (serv.id_s, serv.rne, str(e))) 686 continue 687 if len(erreurs) == len(serveurs): 688 return 0, "Echec de l'exécution ou action interdite sur tous les serveurs" 689 return 1, erreurs
690
691 - def xmlrpc_save_files(self,cred_user,id_serveur,checksum):
692 """sauvegarde des fichiers de configuration d'un serveur""" 693 try: 694 id_serveur = int(id_serveur) 695 serv = self.parent.s_pool.get(cred_user, id_serveur) 696 except (KeyError, ValueError): 697 return 0,u("serveur inconnnu dans la base zephir") 698 module = serv.id_mod 699 variante = serv.id_var 700 archive='fichiers_zephir'+str(id_serveur) 701 public_dir = '/var/spool/uucppublic' 702 temp_dir = public_dir+os.sep+str(id_serveur) 703 # création d'un répertoire temporaire pour éviter que tout le monde 704 # écrive dans le même répertoire 705 if os.path.isdir(temp_dir): 706 shutil.rmtree(temp_dir) 707 try: 708 os.mkdir(temp_dir) 709 except: 710 return 0,u("""erreur de creation du repertoire temporaire""") 711 serveur_dir = serv.get_confdir() 712 # on vérifie la validité de l'archive 713 try: 714 fic_md5 = open(public_dir+os.sep+archive+'.md5','w') 715 fic_md5.write(checksum) 716 fic_md5.close() 717 except: 718 return 0, u("""erreur d'écriture du fichier de checksum""") 719 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir,archive) 720 res=os.system(cmd_md5) 721 if res != 0: 722 return 0,u("""archive corrompue""") 723 else: 724 # l'archive est valide, on la décompresse 725 cmd_tar = """cd %s ; tar -C %s --same-owner -xhpf %s.tar >/dev/null 2>&1""" % (public_dir,str(id_serveur),archive) 726 os.system(cmd_tar) 727 # on met ensuite les fichiers en place 728 # supression des anciens fichiers ? 729 directories = ['dicos','fichiers_perso','patchs','fichiers_zephir'] 730 for rep in directories: 731 if os.path.exists(os.path.join(temp_dir, 'temp_zephir', rep)): 732 try: 733 if rep == 'dicos' and os.path.isdir(os.path.join(os.path.abspath(config.PATH_MODULES),str(module),'dicos')): 734 # creole2 : on conserve module et variante 735 shutil.rmtree(serveur_dir+os.sep+rep+'/local') 736 else: 737 shutil.rmtree(serveur_dir+os.sep+rep) 738 except: 739 # le repertoire (ou fichier) n'existe pas encore 740 pass 741 # on déplace les fichiers de l'archive 742 res = 0 743 for rep in directories: 744 if res == 0: 745 if os.path.exists(os.path.join(temp_dir, 'temp_zephir', rep)): 746 if os.path.isdir(os.path.join(os.path.abspath(config.PATH_MODULES),str(module),'dicos')) and rep == 'dicos': 747 # cas d'eole2 : répertoire de dictionnaires locaux 748 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/'+rep+'/local', os.path.join(serveur_dir,rep))) 749 else: 750 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/'+rep,serveur_dir)) 751 if res == 0: 752 res = os.system('ln -s '+os.path.abspath(config.PATH_MODULES)+os.sep+str(module)+'/variantes/'+str(variante)+os.sep+rep+' '+serveur_dir+os.sep+rep+os.sep+'variante') 753 754 if res != 0: 755 return 0, u("""erreur de mise en place des fichiers""") 756 757 if os.path.exists(os.path.join(temp_dir, 'temp_zephir', 'zephir.eol')): 758 # mise en place de zephir.eol 759 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/zephir.eol',serveur_dir)) 760 if res != 0: 761 return 0, u("""erreur de mise en place de zephir.eol""") 762 else: 763 # mise à jour de l'état du serveur 764 serv.maj_params({'config_ok':1}) 765 766 # vérification des md5 de la configuration 767 serv.check_md5conf() 768 # vidage du répertoire public 769 try: 770 # on supprime les fichiers temporaires 771 os.unlink(public_dir+os.sep+archive+'.tar') 772 os.unlink(public_dir+os.sep+archive+'.md5') 773 shutil.rmtree(temp_dir) 774 except: 775 return 0, u("""erreur de supression des fichiers temporaires""") 776 return 1, u('ok')
777 778
779 - def xmlrpc_install_variante(self,cred_user,id_serveur,checksum,login,passwd_md5):
780 """installation d'une variante pour un module""" 781 try: 782 id_serveur = int(id_serveur) 783 serv = self.parent.s_pool.get(cred_user, id_serveur) 784 except (KeyError, ValueError): 785 return 0,u("serveur inconnnu dans la base zephir") 786 module = serv.id_mod 787 variante = serv.id_var 788 query = """select id,module,owner,passmd5 from variantes where id = %s and module = %s""" 789 params = (int(variante), int(module)) 790 return self.dbpool.runQuery(query, params).addCallbacks(self._install_variante2,db_client_failed,callbackArgs=[cred_user,checksum,login,passwd_md5,serv.get_rne(),id_serveur])
791 792
793 - def _install_variante2(self,data,cred_user,checksum,login,passwd_md5,rne,id_serveur):
794 """vérification de l'archive et stockage des fichiers""" 795 if data == []: 796 return 0, u("""variante non retrouvée dans la base""") 797 variante = data[0][0] 798 module = data[0][1] 799 owner_var = data[0][2] 800 passwd_var= data[0][3] 801 archive='variante'+str(id_serveur) 802 public_dir = '/var/spool/uucppublic' 803 temp_dir = public_dir+os.sep+str(id_serveur) 804 variante_dir = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(module)+os.sep+'variantes'+os.sep+str(variante) 805 # si le mot de passe de la variante n'existe pas (première installation), on le stocke dans la base 806 # si on est propriétaire de la variante : ok 807 if cred_user != owner_var: 808 # si pas de mot de passe : ok 809 if passwd_var not in [None,'']: 810 # sinon on vérifie le mot de passe 811 if passwd_md5 != passwd_var: 812 return 0,u("""erreur, le mot de passe est invalide""") 813 814 # création d'un répertoire temporaire pour éviter que tout le monde 815 # écrive dans le même répertoire 816 if os.path.isdir(temp_dir): 817 shutil.rmtree(temp_dir) 818 try: 819 os.mkdir(temp_dir) 820 except: 821 return 0,u("""erreur de création du repertoire temporaire""") 822 # on vérifie la validité de l'archive 823 try: 824 fic_md5 = open(public_dir+os.sep+archive+'.md5','w') 825 fic_md5.write(checksum) 826 fic_md5.close() 827 except: 828 return 0, u("""erreur d'écriture du fichier de checksum""") 829 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir,archive) 830 res=os.system(cmd_md5) 831 if res != 0: 832 return 0,u("""archive corrompue""") 833 else: 834 # l'archive est valide, on la décompresse 835 cmd_tar = """cd %s ; tar -C %s --same-owner -xhpf %s.tar > /dev/null""" % (public_dir,str(id_serveur),archive) 836 os.system(cmd_tar) 837 # on met ensuite les fichiers en place 838 # supression des anciens patchs et dictionnaires locaux 839 try: 840 shutil.rmtree(variante_dir+os.sep+'dicos') 841 shutil.rmtree(variante_dir+os.sep+'patchs') 842 shutil.rmtree(variante_dir+os.sep+'fichiers_perso') 843 shutil.rmtree(variante_dir+os.sep+'fichiers_zephir') 844 except: 845 return 0, u("""erreur de supression de l'ancienne variante""") 846 # on déplace les fichiers de l'archive 847 res = os.system("mv %s %s" % (temp_dir+os.sep+'patch/variante',variante_dir+os.sep+'patchs')) 848 if res == 0: 849 res = os.system("mv %s %s" % (temp_dir+os.sep+'dicos/variante',variante_dir+os.sep+'dicos')) 850 if res == 0: 851 res = os.system("mv %s %s" % (temp_dir+os.sep+'fichiers_perso',variante_dir+os.sep+'fichiers_perso')) 852 if res == 0: 853 res = os.system("mv %s %s" % (temp_dir+os.sep+'fichiers_zephir',variante_dir+os.sep+'fichiers_zephir')) 854 if res != 0: 855 return 0, u("""erreur de mise en place de la variante""") 856 # vidage du répertoire public 857 try: 858 # on supprime les fichiers temporaires 859 os.unlink(public_dir+os.sep+archive+'.tar') 860 os.unlink(public_dir+os.sep+archive+'.md5') 861 shutil.rmtree(temp_dir) 862 except: 863 return 0, u("""erreur de supression des fichiers temporaires""") 864 865 if passwd_var in [None,'']: 866 # stockage des informations d'authentification 867 query = """update variantes set owner=E%s, passmd5=%s where id = %s and module = %s""" 868 params = (login, passwd_md5, int(variante), int(module)) 869 return self.dbpool.runOperation(query, params).addCallbacks(lambda x : [1,'ok'],lambda x : [0,'erreur de stockage du mot de passe']) 870 else: 871 return 1,u('ok')
872
873 - def xmlrpc_log_serveur(self,cred_user,id_serveur,date,type_action,etat,msg):
874 """ met à jour la table d'état du serveur pour une action précise 875 (ex: MAJ ou CONFIG) afin de refléter l'état de cohérence actuelle du serveur 876 """ 877 params = {'last_log':str(date)} 878 if type_action in ['MAJ','CONFIGURE','RECONFIGURE','SAUVEGARDE','REBOOT','SERVICE_RESTART','UPGRADE','PERSO']: 879 # on met à jour le champs params du serveur pour refléter un éventuel changement d'état 880 if int(etat) == -1: 881 params['%s_ok' % type_action.lower()] = [2, str(date), msg] 882 elif int(etat) > 0: 883 params['%s_ok' % type_action.lower()] = [0, str(date), msg] 884 elif int(etat) == 0: 885 if type_action == "MAJ": 886 # cas spécial, maj lancée : on force query_maj à 0 (plus de paquets non à jour) 887 # params['query_maj'] = [0, str(date)] 888 pass 889 elif type_action == "CONFIGURE": 890 # cas de la fin d'envoi de configuration 891 # on estime que les données de configuration sont synchronisées (md5) 892 # si ce n'est pas le cas, la non concordance sera détectée au prochain envoi de stats 893 md5file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','config%s.md5' % id_serveur) 894 if os.path.isfile(md5file): 895 self.parent.s_pool.edit_serveur(id_serveur,{'md5s':1}) 896 params['md5s'] = [1,""] 897 params['%s_ok' % type_action.lower()] = [1, str(date), msg] 898 elif type_action == 'LOCK': 899 if int(etat) == 1: 900 params['lock_ok'] = [2, str(date), msg] 901 else: 902 params['lock_ok'] = [1,''] 903 try: 904 id_serveur = int(id_serveur) 905 serv = self.parent.s_pool[id_serveur] 906 if serv.version == 'creole1': 907 if params.has_key('query_maj'): 908 params['query_maj'] = [-2,""] 909 except (KeyError, ValueError): 910 return 0,u("serveur inconnnu dans la base zephir") 911 else: 912 # on met à jour la date de dernier contact dans la base 913 self.parent.s_pool.update_contact(id_serveur) 914 915 # on regarde si l'action en question a déjà un état 916 query = """select id,etat,date,type from last_log_serveur where id_serveur=%s and type=E%s""" 917 sql_params = (int(id_serveur), type_action) 918 return self.dbpool.runQuery(query, sql_params).addCallbacks(self._log_serveur,db_client_failed,callbackArgs=[id_serveur,type_action,date,int(etat),msg, params, serv])
919
920 - def _log_serveur(self,data,id_serveur,type_action,date,etat,msg,params,serv):
921 # si l'action existe déjà on la met à jour, sinon on l'insère 922 if data != []: 923 # on insère que si la date du nouveau log est > à l'ancien (cas d'anciens logs non remontés) 924 last_date = data[0][2] 925 try: 926 new_date = datetime.strptime(str(date), "%c") 927 except: 928 try: 929 # problème de conversion de date (pb de locale ?) 930 # on convertit le jour/mois en français 931 new_date = str(date).split() 932 new_date[0] = config.days[new_date[0]] 933 new_date[1] = config.months[new_date[1]] 934 new_date = " ".join(new_date) 935 new_date = datetime.strptime(str(new_date),"%a %b %d %H:%M:%S %Y") 936 except: 937 log.msg("Serveur %s - erreur de lecture de la date pour le log suivant : %s, %s, %s (%s)" % \ 938 (str(id_serveur), type_action, str(etat), msg, date)) 939 log.msg("utilisation de la date courante pour ce log") 940 new_date = datetime.utcnow() 941 if new_date >= last_date: 942 query = """update last_log_serveur set id_serveur=%s,date=%s,type=E%s,message=E%s,etat=%s where id=%s""" 943 sql_params = (int(id_serveur), date, type_action, msg, int(etat), int(data[0][0])) 944 # on met à jour le champs params et le cache mémoire 945 #if params.has_key('query_maj'): 946 # self.parent.s_pool.edit_serveur(id_serveur,{'maj':params['query_maj'][0]}) 947 serv.maj_params(params) 948 else: 949 # on a reçu un ancien log (reprise d'anciens logs ayant échoué) -> pas de maj de last_log 950 return self._log_serveur2(None,id_serveur,type_action,date,etat,msg) 951 else: 952 query = """insert into last_log_serveur (id_serveur,date,type,message,etat) values (%s,%s,E%s,E%s,%s)""" 953 sql_params = (int(id_serveur), date, type_action, msg, int(etat)) 954 # on met à jour le champs params et le cache mémoire 955 #if params.has_key('query_maj'): 956 # self.parent.s_pool.edit_serveur(id_serveur,{'maj':params['query_maj'][0]}) 957 serv.maj_params(params) 958 return self.dbpool.runOperation(query, sql_params).addCallbacks(self._log_serveur2,db_client_failed,callbackArgs=[id_serveur,type_action,date,etat,msg])
959
960 - def _log_serveur2(self,data,id_serveur,type_action,date,etat,msg):
961 query = """insert into log_serveur (id_serveur,date,type,message,etat) values (%s,%s,E%s,E%s,%s)""" 962 sql_params = (int(id_serveur), date, type_action, msg, etat) 963 # on effectue la mise à jour de la base 964 return self.dbpool.runOperation(query, sql_params).addCallbacks(lambda x : [1,'ok'],db_client_failed)
965
966 - def xmlrpc_release_lock_groupe(self,cred_user,liste):
967 """prépare la suppression des verrous sur un groupe""" 968 erreurs=[] 969 for serveur in liste: 970 retour = self.xmlrpc_release_lock(cred_user, serveur['id']) 971 if retour[0] == 0: 972 erreurs.append(str(serveur['id'])+' : '+retour[1]) 973 if erreurs != []: 974 return 0,u(erreurs) 975 else: 976 return 1, u('ok')
977
978 - def xmlrpc_release_lock(self,cred_user,id_serveur):
979 """demande la libération des verrous sur un serveur""" 980 try: 981 id_serveur = int(id_serveur) 982 serv = self.parent.s_pool.get(cred_user,id_serveur) 983 except (KeyError, ValueError): 984 return 0,u("serveur inconnnu dans la base zephir") 985 else: 986 serv.maj_params({'del_locks':True}) 987 return 1, 'ok'
988
989 - def xmlrpc_unlock(self,cred_user,id_serveur,unlocked=False):
990 """indique si les locks doivent être ignorés 991 @params unlocked: si True, on enlève l'attibut del_lock de params""" 992 try: 993 id_serveur = int(id_serveur) 994 serv = self.parent.s_pool.get(cred_user,id_serveur) 995 except (KeyError, ValueError): 996 return 0,u("serveur inconnnu dans la base zephir") 997 params = serv.get_params() 998 if params.has_key('del_locks'): 999 if params['del_locks'] == True: 1000 if unlocked: 1001 # les verrous ont été supprimés, on revient en état normal 1002 serv.maj_params({'del_locks':False}) 1003 # les verrous doivent être bypassés 1004 return 1, True 1005 return 1, False
1006
1007 - def _sendmail(self,adresses,subject,msg):
1008 """envoi d'un message d'alerte à une liste d'adresses mail 1009 """ 1010 bad_addr={} 1011 mail = email.MIMEText.MIMEText(msg) 1012 mail['Subject'] = Header("[Zephir] %s" % subject,"utf-8") 1013 mail['From'] = Header(config.MAIL_ACCOUNT, "utf-8") 1014 mail.set_charset('UTF-8') 1015 mail_client=smtplib.SMTP() 1016 orig_timeout = smtplib.socket.getdefaulttimeout() 1017 try: 1018 smtplib.socket.setdefaulttimeout(3) 1019 if config.MAIL_PORT != '': 1020 mail_client.connect(config.MAIL_ADRESSE,config.MAIL_PORT) 1021 else: 1022 mail_client.connect(config.MAIL_ADRESSE) 1023 smtplib.socket.setdefaulttimeout(orig_timeout) 1024 except: 1025 smtplib.socket.setdefaulttimeout(orig_timeout) 1026 return 0, u('erreur de connexion au serveur smtp') 1027 else: 1028 try: 1029 mail_client.helo() 1030 bad_addr = mail_client.sendmail(config.MAIL_ACCOUNT,adresses,mail.as_string()) 1031 except: 1032 return 0, u("erreur d'envoi du mail d'alerte") 1033 return 1, bad_addr
1034 1035
1036 - def xmlrpc_maj_site(self,cred_user,ip_publique,id_serveur,checksum,new_agents=0):
1037 """vérifie l'archive envoyée par le serveur et met le site et les données xml en place 1038 """ 1039 log.msg ("connexion du serveur %s" % str(id_serveur)) 1040 # on regarde dans les logs si un lock est indiqué 1041 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD) 1042 query="""select type,etat from last_log_serveur where id_serveur=%s and type='LOCK' order by date desc, id desc""" 1043 cursor=cx.cursor() 1044 cursor.execute(query, (int(id_serveur),)) 1045 data=cursor.fetchall() 1046 cursor.close() 1047 cx.close() 1048 etat=0 1049 if data != []: 1050 etat=int(data[0][1]) 1051 if etat == 1: 1052 # si il y avait un lock sur uucp, on l'annule 1053 self.xmlrpc_log_serveur(cred_user,id_serveur,str(time.ctime()),'LOCK','0',"""Reprise de l'activité uucp""") 1054 # on met à jour la date de dernier contact dans la base 1055 self.parent.s_pool.update_contact(id_serveur) 1056 # vérification du md5 de l'archive 1057 public_dir = '/var/spool/uucppublic' 1058 archive = 'site%s' % id_serveur 1059 try: 1060 fic_md5 = open(public_dir+os.sep+archive+'.md5','w') 1061 fic_md5.writelines(checksum) 1062 fic_md5.close() 1063 except: 1064 return 0, u("""erreur d'écriture du fichier de checksum""") 1065 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir, archive) 1066 res=os.system(cmd_md5) 1067 if res != 0: 1068 return 0,u("""archive corrompue""") 1069 else: 1070 compressed='' 1071 # l'archive est valide, on la décompresse 1072 if int(new_agents) == 1: 1073 # l'archive est zippée avec les nouveaux agents 1074 compressed = 'z' 1075 rep_dest = os.path.abspath(config.PATH_ZEPHIR) 1076 # on supprime l'ancien répertoire 1077 try: 1078 shutil.rmtree(rep_dest+os.sep+"data"+os.sep+str(id_serveur)) 1079 except: 1080 pass 1081 else: 1082 rep_dest = os.path.abspath(config.PATH_ZEPHIR)+os.sep+"sites"+os.sep+str(id_serveur) 1083 # on supprime l'ancien répertoire 1084 if os.path.exists(rep_dest): 1085 shutil.rmtree(rep_dest) 1086 os.makedirs(rep_dest) 1087 1088 cmd_tar = """cd %s ; /bin/tar -C %s -x%sf %s.tar 2> /dev/null""" % (public_dir, rep_dest, compressed, archive) 1089 res=os.system(cmd_tar) 1090 if res != 0: 1091 return 0,u("erreur de mise en place du site sur zephir") 1092 serv = self.parent.s_pool[int(id_serveur)] 1093 serv.check_md5conf() 1094 serv.check_maj_status() 1095 serv.update_ip_pub(ip_publique) 1096 if int(new_agents) == 1 and serv.version == 'creole1': 1097 # si serveur eole 1, on convertit le xml en utf-8 1098 f_site = file(os.path.join(rep_dest,'data',str(id_serveur),'site.cfg')) 1099 data = f_site.read() 1100 f_site.close() 1101 try: 1102 data = unicode(data,'ISO-8859-1').encode(config.charset) 1103 except: 1104 pass 1105 else: 1106 f_site = file(os.path.join(rep_dest,'data',str(id_serveur),'site.cfg'),'w') 1107 f_site.write(data) 1108 f_site.close() 1109 for xml_file in glob.glob(os.path.join(rep_dest,'data',str(id_serveur),'*/agent.xml')): 1110 try: 1111 xml = file(xml_file).read() 1112 # conversion du contenu 1113 for ori, dst in config.xml_table.items(): 1114 xml = xml.replace(ori,dst) 1115 file(xml_file,'w').write(xml) 1116 except: 1117 log.msg("erreur lors de la conversion de %s en %s" % (xml_file, config.charset)) 1118 # on met à jour la liste d'agents (en cas de nouvel agent) 1119 # et on regarde si un des agents a remonté une erreur 1120 list_errors = [] 1121 try: 1122 if self.agent_manager.has_key(str(id_serveur)): 1123 # nouvelle API des agents 1124 # on force un update du cache pour ce serveur (prise en compte de nouveaux agents sans redémarrer l'application) 1125 self.agent_manager[str(id_serveur)].update_structure() 1126 stats = self.agent_manager[str(id_serveur)].get_measure() 1127 result_ag = self.agent_manager[str(id_serveur)].global_status() 1128 if result_ag == 0: 1129 # détail des agents en erreur 1130 liste_errors = [] 1131 for ag_name, detail_ag in self.agent_manager[str(id_serveur)].agents_status().items(): 1132 if detail_ag[1] == 0 and ag_name != 'tcpservices': 1133 list_errors.append(detail_ag[0]) 1134 else: 1135 # anciens agents 1136 # mise à jour des données depuis les xml remontés 1137 AgentCollecteur(id_serveur) 1138 result_ag = ServeurStatus(id_serveur).get_status() 1139 except: 1140 traceback.print_exc() 1141 result_ag = 1 1142 1143 # on vérifie la cohérence du serveur au niveau des logs zephir 1144 try: 1145 result_zeph = self.parent.getSubHandler('serveurs').xmlrpc_get_status(cred_user,id_serveur) 1146 except: 1147 return 0, u("erreur de récupération de l'état zephir du serveur %s" % id_serveur) 1148 1149 d = defer.Deferred() 1150 d.addCallback(self._alerte,result_zeph[1],result_ag,list_errors) 1151 d.callback(id_serveur) 1152 1153 return 1,u("ok")
1154 1155
1156 - def _alerte(self,id_serveur,etat_zeph,etat_ag,list_errors):
1157 """vérification de l'état du serveur et envoi mail si nécessaire 1158 """ 1159 # on récupére la liste des utilisateurs à contacter 1160 query="select serveurs.id,serveurs.rne,installateur,serveurs.libelle, \ 1161 modules.libelle,etablissements.libelle,serveurs.etat,serveurs.params \ 1162 from serveurs,etablissements,modules \ 1163 where serveurs.id=%s and etablissements.rne=serveurs.rne and modules.id=module_actuel" 1164 self.dbpool.runQuery(query, (int(id_serveur),)).addCallbacks(self._alerte2,db_client_failed,callbackArgs=[etat_zeph,etat_ag,list_errors])
1165
1166 - def _alerte2(self,data,etat_zeph,etat_ag,list_errors):
1167 # si erreur zephir ou agent --> mail 1168 if data == []: 1169 # pas de données récupérées (serveur inexistant ?) 1170 pass 1171 else: 1172 id_serveur = data[0][0] 1173 rne = data[0][1] 1174 libelle = data[0][3] 1175 module = data[0][4] 1176 libel_etab = data[0][5] 1177 etat_precedent = data[0][6] 1178 if etat_precedent != None: 1179 try: 1180 etat_precedent = int(etat_precedent) 1181 except Exception, e: 1182 etat_precedent = 1 1183 erreur = 0 1184 msg = """le serveur %s (%s - %s)\n établissement : %s (%s)""" % (libelle, id_serveur, module, rne, libel_etab) 1185 # vérification de l'état du serveur 1186 for cle in etat_zeph.keys(): 1187 etat = etat_zeph[cle] 1188 if type(etat) == list: 1189 if len(etat) == 3: 1190 if etat[0] == 0: 1191 if erreur == 0: 1192 msg += """\n(se reporter à la page d'état du serveur dans l'application web)""" 1193 erreur = 1 1194 msg +="""\n\nlog du %s : %s""" % (etat[1].encode(config.charset),etat[2].encode(config.charset)) 1195 if (cle == 'lock_ok') and (etat[0] != 1): 1196 msg += """\n\n Fonction Zephir verrouillées, connectez vous sur le serveur pour vérifier son état 1197 (commande '/usr/share/zephir/scripts/zephir_client del_lock' pour déverrouiller)""" 1198 1199 # on stocke l'etat global des agents dans le champs params du serveur 1200 serv = self.parent.s_pool[id_serveur] 1201 try: 1202 params=eval(data[0][7]) 1203 assert type(params) == dict 1204 params['agents'] = etat_ag 1205 except: 1206 # pas encore de données dans params 1207 params = {'agents':etat_ag} 1208 serv.maj_params(params) 1209 1210 if etat_ag == 0: 1211 erreur = 2 1212 # erreur remontée dans le site de surveillance 1213 msg += """\n\nerreur remontée par le serveur (cf. https://%s:%s/agents/%s)""" % (config.ADRESSE_ZEPHIR,config.PORT_HTTP,id_serveur) 1214 if list_errors != []: 1215 msg += """\n\n* %s""" % "\n* ".join(list_errors) 1216 1217 # envoi de message si erreur non envoyée précédemment 1218 # on regarde le dernier état enregistré pour ce serveur 1219 if erreur != 0: 1220 if etat_precedent not in [0,4]: 1221 if etat_precedent == 3: 1222 serv.set_status(4) 1223 else: 1224 serv.set_status(0) 1225 if serv.no_alert == False: 1226 # début d'alerte 1227 if etat_precedent == 2: 1228 # on vient de reprendre contact et il y a un problème 1229 subject = "problème détecté à la reprise de contact: serveur %s (%s)" % (libelle,rne) 1230 else: 1231 subject = "problème détecté : serveur %s (%s)" % (libelle,rne) 1232 msg = "\nproblème détecté sur " + msg 1233 self._send_alerte("problème détecté : serveur ",{int(id_serveur):msg}) 1234 else: 1235 # pas d'erreur détectée, si l'état était à 2, on ne le change pas 1236 # (l'état sera remis à 1 par la fonction de vérification du timeout) 1237 if etat_precedent in [0,4]: 1238 if etat_precedent == 4: 1239 serv.set_status(3) 1240 else: 1241 serv.set_status(1) 1242 if serv.no_alert == False: 1243 # fin d'alerte 1244 subject = "fin d'alerte : serveur %s (%s)" % (libelle,rne) 1245 msg = "\n fin d'alerte pour " + msg 1246 self._send_alerte("fin d'alerte : ",{int(id_serveur):msg}) 1247 # si on n'avait pas d'info : etat ok 1248 if etat_precedent == None: 1249 serv.set_status(1)
1250
1251 - def _send_alerte(self,subject,msgs):
1252 """recherche les mails et sms des personnes surveillant un serveur particulier 1253 """ 1254 if msgs != {}: 1255 query = """select id,serveurs from groupes_serveurs""" 1256 self.dbpool.runQuery(query).addCallbacks(self._send_alerte2,db_client_failed,callbackArgs=[subject,msgs])
1257
1258 - def _send_alerte2(self,data,subject,msg):
1259 # on récupère les groupes 1260 # et on regarde quels groupes contiennent ce serveur 1261 groupes=[] 1262 for id_serveur in msg.keys(): 1263 for groupe in data: 1264 if id_serveur in eval(groupe[1]): 1265 if groupe[0] not in groupes: 1266 groupes.append(groupe[0]) 1267 query = """select groupes,mail,sms,mail_actif,sms_actif from users \ 1268 where groupes != '' and (mail_actif=1 or sms_actif=1)""" 1269 self.dbpool.runQuery(query).addCallbacks(self._send_alerte3,db_client_failed,callbackArgs=[groupes,subject,msg])
1270
1271 - def _send_alerte3(self,data,groupes,subject,msg):
1272 """regarde quels utilisateurs surveillent les groupes 1273 en question et envoie un mail ou sms si besoin 1274 """ 1275 # utilisateurs avec les bons groupes 1276 destinataires = [] 1277 for user in data: 1278 try: 1279 groupes_user=eval(user[0]) 1280 except: 1281 groupes_user=[] 1282 for groupe in groupes_user: 1283 # un des groupes contient ce serveur 1284 if groupe in groupes: 1285 # on regarde si il faut envoyer des mails ou sms 1286 if user[3]==1: 1287 # on vérifie la syntaxe de l'adresse mail 1288 for adresse in user[1].split(','): 1289 r=re.match("""^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9]+)*$""",adresse) 1290 if r is not None: 1291 # adresse valide : on envoie le mail 1292 if adresse not in destinataires: 1293 destinataires.append(adresse) 1294 # envoi effectif des messages à tous les utilisateurs concernés 1295 if destinataires != []: 1296 self._sendmail(destinataires,subject + str(msg.keys()),"\n".join(msg.values()))
1297
1298 - def xmlrpc_scan_timeouts(self,*args):
1299 """vérifie toutes les x minutes si des serveurs ont dépassé leur timeout. 1300 vérification toutes les 5 miuntes par défaut""" 1301 # requete de récupération des données 1302 try: 1303 # premier démarrage de la boucle de vérification des contacts 1304 if self.start_time is not None: 1305 query = "update serveurs set last_contact=%s where last_contact is not null and etat <> 2" 1306 self.dbpool.runOperation(query, (self.start_time,)).addCallbacks(lambda x : [1, "OK"],db_client_failed) 1307 reactor.callLater(5, self._scan_timeouts) 1308 self.start_time = None 1309 # self.parent.scheduler.start() 1310 except: 1311 traceback.print_exc() 1312 return 0, "erreur de démarrage de la boucle de surveillance" 1313 return 1,""
1314
1315 - def _scan_timeouts(self):
1316 reactor.callLater(self.scan_delay,self._scan_timeouts) 1317 if config.LOG_ACTIONS: 1318 log.msg('Recherche des pertes de contact') 1319 query = """select serveurs.id,timeout,last_contact,serveurs.libelle, \ 1320 serveurs.rne,etablissements.libelle,modules.libelle,serveurs.etat \ 1321 from serveurs,etablissements,modules where timeout > 0 and last_contact is not null and \ 1322 serveurs.rne=etablissements.rne and module_actuel=modules.id""" 1323 self.dbpool.runQuery(query).addCallbacks(self._scan_timeouts2,db_client_failed)
1324
1325 - def _scan_timeouts2(self,data):
1326 """vérifie si le dernier contact est moins ancien que le timeout du serveur. 1327 """ 1328 erreurs={} 1329 reprises={} 1330 bloquages={} 1331 debloquages={} 1332 cmds=uucp_pool._scan_pool() 1333 for serveur in data: 1334 # calcul du temps écoulé depuis le dernier contact (en secondes) 1335 serv = self.parent.s_pool[int(serveur[0])] 1336 params = {'timeout':[-2, ""]} 1337 last = float(serveur[2]) 1338 delta = float(time.time()) - last 1339 try: 1340 etat_actuel = int(serveur[7]) 1341 except: 1342 etat_actuel = 1 1343 # on regarde si on a dépassé le timeout 1344 try: 1345 timeout = int(serveur[1]) 1346 except: 1347 pass 1348 else: 1349 params['timeout'] = [1, time.ctime(last)] 1350 # on laisse un délai de 2x le délai de connexion + 4 minutes avant de lever une alerte 1351 # (on autorise de rater une connexion) 1352 max_delay = int(timeout) * 2 + 240 1353 if ( delta > max_delay ) and timeout != 0: 1354 params['timeout'][0]=0 1355 if etat_actuel != 2: 1356 # on prévient les utilisateurs concernés si ce n'est pas déjà fait 1357 log.msg("timeout du serveur %s" % serveur[0]) 1358 serv.set_status(2) 1359 # construction du message d'erreur 1360 if serv.no_alert == False: 1361 subject = """perte du contact : serveur(s) %s (%s)""" % (serveur[3],serveur[4]) 1362 msg="""Dernier contact avec le serveur n°%s - %s (%s) de l'établissement %s (%s) : %s""" % (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5],time.ctime(last)) 1363 # ajout de l'alerte 1364 erreurs[serveur[0]]=msg 1365 else: 1366 if etat_actuel == 2: 1367 # on était en timeout auparavant 1368 serv.set_status(1) 1369 if serv.no_alert == False and timeout != 0: 1370 subject = """reprise du contact : serveur(s) %s (%s)""" % (serveur[3],serveur[4]) 1371 msg = """reprise du contact avec le serveur n°%s - %s (%s) de l'établissement %s (%s) : %s""" % \ 1372 (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5],time.ctime(last)) 1373 reprises[serveur[0]]=msg 1374 1375 # vérification de la bonne exécution des commandes 1376 id_uucp = serveur[4]+"-"+str(serveur[0]) 1377 old_cmds = uucp_pool.check_timeout(max_delay, id_uucp) 1378 if old_cmds != {} and timeout != 0: 1379 if etat_actuel not in [3,4]: 1380 # mail pour le bloquage des commandes en attente 1381 if serv.no_alert == False: 1382 msg = """commandes bloquées en attente pour le serveur n°%s - %s (%s) de l'établissement %s (%s) 1383 Vous pouvez afficher les logs de transfert UUCP sur ce serveur à l'aide de la commande uulog""" 1384 bloquages[serveur[0]] = msg % (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5]) 1385 if etat_actuel == 0: 1386 # bloquage + erreur agents 1387 serv.set_status(4) 1388 else: 1389 # bloquage 1390 serv.set_status(3) 1391 elif etat_actuel in [3,4]: 1392 # les commandes sont débloquées 1393 if serv.no_alert == False and timeout != 0: 1394 msg = """débloquage des commandes (reprise d'activité uucp) pour le serveur n°%s - %s (%s) de l'établissement %s (%s)""" 1395 debloquages[serveur[0]] = msg % (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5]) 1396 if etat_actuel == 4: 1397 # erreur agents 1398 serv.set_status(0) 1399 else: 1400 # aucune erreur 1401 serv.set_status(1) 1402 1403 # mise à jour du champ params du serveur 1404 serv.maj_params(params) 1405 1406 self._send_alerte("commandes non lancées : ",bloquages) 1407 self._send_alerte("commandes débloquées : ",debloquages) 1408 self._send_alerte("perte de contact : ",erreurs) 1409 self._send_alerte("reprise du contact : ",reprises)
1410
1411 - def xmlrpc_get_actions(self,cred_user,id_serveur):
1412 """retourne la liste des actions uucp en attente""" 1413 # on vérifie l'existence du serveur dans la base 1414 try: 1415 id_serveur = int(id_serveur) 1416 serv = self.parent.s_pool.get(cred_user, id_serveur) 1417 except (KeyError, ValueError): 1418 return 0,u("serveur inconnnu dans la base zephir") 1419 else: 1420 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 1421 # construction de la commande 1422 try: 1423 cmds=uucp_pool.list_cmd(id_uucp)[id_uucp] 1424 except: 1425 cmds={} 1426 try: 1427 files=uucp_pool.list_files(id_uucp)[id_uucp] 1428 except: 1429 files={} 1430 return 1,u([cmds,files])
1431
1432 - def xmlrpc_check_queue(self,cred_user,id_serveur):
1433 """indique à un serveur si il doit ou non effectuer des actions 1434 """ 1435 # on vérifie l'existence du serveur dans la base 1436 try: 1437 id_serveur = int(id_serveur) 1438 serv = self.parent.s_pool.get(cred_user, id_serveur) 1439 except (KeyError, ValueError): 1440 return 0,u("serveur inconnnu dans la base zephir") 1441 else: 1442 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur) 1443 # on commence par mettre à jour le pool uucp 1444 cmds=uucp_pool._scan_pool() 1445 if len(uucp_pool.pool[id_uucp]) > 0: 1446 return 1, True 1447 else: 1448 return 1, False
1449
1450 - def xmlrpc_purge_actions(self,cred_user,serveurs,id_tache=None):
1451 """annule toutes les actions en attente sur un/plusieurs serveur(s)""" 1452 # on vérifie l'existence du serveur dans la base 1453 try: 1454 for id_serveur in serveurs: 1455 id_serveur = int(id_serveur) 1456 assert self.parent.s_pool.has_key(id_serveur) 1457 except (KeyError, ValueError): 1458 return 0,u("serveur inconnnu dans la base zephir") 1459 else: 1460 for id_serveur in serveurs: 1461 rne = self.parent.s_pool.get(cred_user,int(id_serveur)).get_rne() 1462 id_uucp = str(rne) + '-' + str(id_serveur) 1463 # on regarde si un transfert est lié à cette action (configure) 1464 if id_tache is None: 1465 try: 1466 uucp_pool.flush([id_uucp]) 1467 except UUCPError, e: 1468 return 0, u("erreur de purge des commandes : %" % str(e)) 1469 else: 1470 try: 1471 uucp_pool.remove_cmd(id_uucp,int(id_tache)) 1472 except UUCPError, e: 1473 return 0,u("Erreur de supression de la commande uucp : %" %str(e)) 1474 except KeyError: 1475 pass 1476 1477 return 1,"OK"
1478