1
2
3
4
5
6
7
8
9
10
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
19 from zephir.backend.xmlrpceole import XMLRPCEole as XMLRPC
20 from zephir.monitor.collecteur import AgentCollecteur, ServeurStatus
21 from twisted.enterprise import adbapi
22 from twisted.internet import defer, reactor
23 from twisted.python import log
24
25 import sys,os,shutil,time,smtplib,re,time,base64,glob
26 from datetime import datetime
27 import traceback
28 import psycopg2 as PgSQL
29 from cStringIO import StringIO
30
31
33 """serveur XMLRPC zephir pour la gestion des actions sur les serveurs
34 """
35
36 - def __init__(self,parent,agent_manager,bdd='zephir-parc'):
37 self.dbpool = db_connect()
38 self.dbpool.noisy = 0
39 XMLRPC.__init__(self)
40 self.agent_manager = agent_manager
41 self.parent=parent
42
43
44 self.scan_delay = config.SCAN_DELAY
45
46
47 self.start_time = str(time.time())
48
50 """met en queue des fichiers ou répertoires pour un serveur distant
51 et stocke la somme md5 des fichiers envoyés dans le fichier cheksum.txt du
52 systeme en question (dans zephir/conf/rne/serveur/)"""
53
54 id_uucp = str(serv.get_rne())+'-'+str(serv.id_s)
55
56 serveur_dir = serv.get_confdir()
57 cmd_tar = ['cd ',serveur_dir,';','/bin/tar','--same-owner','-chpf',archive+'.tar']
58
59 for fic in files:
60
61 if os.path.isfile(serveur_dir+os.sep+fic) or os.path.isdir(serveur_dir+os.sep+fic):
62 cmd_tar.append(fic)
63 else:
64
65 if fic not in ['dico.eol','zephir.eol', 'droits_variante', 'droits_zephir']:
66
67 return 0, u("""fichier %s introuvable""" % serveur_dir+os.sep+fic)
68 cmd_tar.append('>/dev/null 2>&1')
69 res=os.system(" ".join(cmd_tar))
70 if res != 0:
71 return 0, u("""erreur de creation de l'archive %s.tar dans %s""" % (archive,serveur_dir))
72
73 cmd_checksum = """cd %s ;md5sum -b %s.tar > %s.md5""" % (serveur_dir,archive,archive)
74 os.system(cmd_checksum)
75 if uucp:
76
77 try:
78 res = uucp_pool.add_file(id_uucp,serveur_dir+os.sep+archive+".tar")
79 except UUCPError,e:
80 return 0, u("Erreur UUCP %s" % str(e))
81 return 1,u(archive+'.tar')
82
97
99 """prépare le redémarrage d'un service sur un groupe"""
100 erreurs=[]
101 for serveur in liste:
102 retour = self.xmlrpc_service_restart(cred_user, serveur['id'], service)
103 if retour[0] == 0:
104 erreurs.append(str(serveur['id'])+' : '+retour[1])
105 if erreurs != []:
106 return 0,u(erreurs)
107 else:
108 return 1, u('ok')
109
111 """exécution de la commande uucp pour redémarrer un service"""
112 try:
113 id_serveur = int(id_serveur)
114 serv = self.parent.s_pool.get(cred_user, id_serveur)
115 except KeyError, ValueError:
116 return 0,u("serveur inconnnu dans la base zephir")
117 else:
118 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
119
120 try:
121 uucp_pool.add_cmd(id_uucp,"zephir_client service_restart %s" % service)
122 except UUCPError,e:
123 return 0, u("erreur uucp (%s)" % str(e))
124 return 1,u("ok")
125
127 """prépare le redémarrage d'un groupe de serveurs"""
128 erreurs=[]
129 for serveur in liste:
130 retour = self.xmlrpc_reboot(cred_user, serveur['id'])
131 if retour[0] == 0:
132 erreurs.append(str(serveur['id'])+' : '+retour[1])
133 if erreurs != []:
134 return 0,u(erreurs)
135 else:
136 return 1, u('ok')
137
139 """exécution de la commande uucp pour redémarrer un serveur"""
140 try:
141 id_serveur = int(id_serveur)
142 serv = self.parent.s_pool.get(cred_user, id_serveur)
143 except KeyError, ValueError:
144 return 0,u("serveur inconnnu dans la base zephir")
145 else:
146 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
147
148 try:
149 uucp_pool.add_cmd(id_uucp,"zephir_client reboot")
150 except UUCPError,e:
151 return 0, u("serveur %s : erreur uucp (%s)" % (str(id_serveur), str(e)))
152 return 1,u("ok")
153
154
160
173
174
226
228 """prépare la sauvegarde de configuration d'un serveur"""
229
230 return self._save_conf(cred_user, id_serveur)
231
232
234 """prépare la sauvegarde de configuration d'un serveur"""
235 erreurs=[]
236 for serveur in liste:
237 retour = self._save_conf(cred_user, serveur['id'])
238 if retour[0] == 0:
239 erreurs.append(str(serveur['id'])+' : '+retour[1])
240 if erreurs != []:
241 return 0,u(erreurs)
242 else:
243 return 1, u('ok')
244
245
247 """exécution de la commande uucp pour la mise à jour"""
248 try:
249 id_serveur = int(id_serveur)
250 serv = self.parent.s_pool.get(cred_user, id_serveur)
251 except KeyError, ValueError:
252 return 0,u("serveur inconnnu dans la base zephir")
253 else:
254 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
255
256 try:
257 uucp_pool.add_cmd(id_uucp,"zephir_client save_files")
258 except UUCPError,e:
259 return 0, u("erreur uucp (%s)" % str(e))
260 return 1,u("ok")
261
262 - def xmlrpc_maj(self,cred_user,id_serveur,reconf = 0, delay = ""):
263 """prépare la mise à jour d'un serveur Eole par l'intermédiare d'uucp"""
264
265 return self._maj(cred_user, id_serveur, reconf, delay)
266
268 """prépare la mise à jour d'un groupe de serveurs Eole par l'intermédiare d'uucp"""
269 erreurs=[]
270 for serveur in liste:
271 retour = self._maj(cred_user, serveur['id'],reconf,delay)
272 if retour[0] == 0:
273 erreurs.append("serveur "+str(serveur['id'])+' : '+retour[1])
274 if erreurs != []:
275 return 0,u(erreurs)
276 else:
277 return 1, u('ok')
278
279 - def _maj(self,cred_user, id_serveur, reconf,delay):
280 """exécution de la commande uucp pour la mise à jour"""
281 try:
282 id_serveur = int(id_serveur)
283 serv = self.parent.s_pool.get(cred_user,id_serveur)
284 except KeyError, ValueError:
285 return 0,u("serveur inconnnu dans la base zephir")
286 else:
287 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
288
289 try:
290 assert int(delay) > 0
291 except:
292 delay = ""
293 try:
294 uucp_pool.add_cmd(id_uucp,"zephir_client maj_auto %s" % str(delay))
295 except UUCPError, e:
296 return 0, u("Erreur UUCP (%s)" % str(e))
297
298
299
300 if reconf == 1:
301 return self.xmlrpc_reconfigure(cred_user, id_serveur)
302 else:
303 return 1, u("ok")
304
305
307 """prépare la mise à jour de zephir-client sur un serveur"""
308
309 return self._maj_client(cred_user, id_serveur)
310
312 """prépare la mise à jour de zephir-client sur un groupe de serveurs"""
313 erreurs=[]
314 for serveur in liste:
315 retour = self._maj_client(cred_user, serveur['id'])
316 if retour[0] == 0:
317 erreurs.append("serveur "+str(serveur['id'])+' : '+retour[1])
318 if erreurs != []:
319 return 0, u(erreurs)
320 else:
321 return 1, u('ok')
322
324 """exécution de la commande uucp pour la mise à jour de zephir-client"""
325 try:
326 id_serveur = int(id_serveur)
327 serv = self.parent.s_pool.get(cred_user,id_serveur)
328 except KeyError, ValueError:
329 return 0,u("serveur inconnnu dans la base zephir")
330 else:
331 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
332
333 try:
334 uucp_pool.add_cmd(id_uucp,"zephir_client maj_client")
335 except UUCPError, e:
336 return 0, u("Erreur UUCP (%s)" % str(e))
337 else:
338 return 1, u("ok")
339
341 """stocke la configuration vpn d'un amon vers ce sphynx"""
342 try:
343 id_sphynx = int(id_sphynx)
344 id_amon = int(id_amon)
345 sphynx = self.parent.s_pool.get(cred_user,id_sphynx)
346 amon = self.parent.s_pool.get(cred_user,id_amon)
347 except KeyError, ValueError:
348 return 0,u("serveur inconnnu dans la base zephir")
349
350 if not amon.get_module().startswith('amon-'):
351 return 0, "serveur invalide : %s" % str(id_amon)
352
353 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD)
354 cursor=cx.cursor()
355 query = """select id_amon from conf_vpn where id_sphynx=%s""" % id_sphynx
356 cursor.execute(query)
357 data=cursor.fetchall()
358 cursor.close()
359 cx.close()
360
361
362 sphynx_dir = sphynx.get_confdir()
363 if not os.path.exists(sphynx_dir + os.sep + 'vpn'):
364 os.makedirs(sphynx_dir + os.sep + 'vpn')
365 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz'
366
367 confs = [ligne[0] for ligne in data]
368 if int(id_amon) in confs:
369
370 query = """update conf_vpn set etat=%s where id_sphynx=%s and id_amon=%s""" % (0,int(id_sphynx),int(id_amon))
371 else:
372
373 query = """insert into conf_vpn (id_sphynx,id_amon,etat) values (%s,%s,%s)""" % (int(id_sphynx),int(id_amon),0)
374 return self.dbpool.runOperation(query).addCallbacks(self._sphynx_add,db_client_failed,callbackArgs=[archive,content])
375
377 """écriture de la conf vpn"""
378 try:
379 file = StringIO()
380 data = base64.decodestring(content)
381 fd = open(archive,'wb')
382
383 file.write(data)
384 file.seek(0)
385 fd.write(file.read())
386 fd.close()
387 except:
388 return 0, u("erreur de sauvegarde de l'archive")
389 return 1, "OK"
390
392 """supprime la configuration vpn d'un amon vers ce sphynx"""
393 try:
394 id_sphynx = int(id_sphynx)
395 id_amon = int(id_amon)
396 sphynx = self.parent.s_pool.get(cred_user,id_sphynx)
397 amon = self.parent.s_pool.get(cred_user,id_amon)
398 except KeyError, ValueError:
399 return 0,u("serveur inconnnu dans la base zephir")
400 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD)
401 cursor=cx.cursor()
402 query = """select etat from conf_vpn where id_sphynx=%s and id_amon=%s""" % (str(id_sphynx),str(id_amon))
403 cursor.execute(query)
404 data=cursor.fetchone()
405 etat = data[0]
406 cursor.close()
407 cx.close()
408 try:
409
410 sphynx_dir = sphynx.get_confdir()
411 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz'
412 os.unlink(archive)
413 except:
414 if del_row == 0:
415 return 0, u("fichier de configuration vpn non supprimé (ou inexistant)")
416 if del_row == 1:
417 query = """delete from conf_vpn where id_sphynx=%s and id_amon=%s""" % (id_sphynx,id_amon)
418 else:
419 nouv_etat=2
420
421 if int(etat) == 0:
422 nouv_etat=3
423 query = """update conf_vpn set etat=%s where id_sphynx=%s and id_amon=%s""" % (nouv_etat,id_sphynx,id_amon)
424 return self.dbpool.runOperation(query).addCallbacks(lambda x : [1,u("OK")],db_client_failed)
425
427 """envoie la configuration vpn d'un amon vers ce sphynx"""
428 try:
429 id_sphynx = int(id_sphynx)
430 id_amon = int(id_amon)
431 sphynx = self.parent.s_pool.get(cred_user,id_sphynx)
432 amon = self.parent.s_pool.get(cred_user,id_amon)
433 except KeyError, ValueError:
434 return 0,u("serveur inconnnu dans la base zephir")
435 try:
436
437 sphynx_dir = sphynx.get_confdir()
438 archive = sphynx_dir + os.sep + 'vpn' + os.sep + str(id_amon) + '.tar.gz'
439 file_conf=open(archive)
440 content=base64.encodestring(file_conf.read())
441 file_conf.close()
442 except:
443 return 0, u("fichier de configuration vpn non trouvé")
444 query = """update conf_vpn set etat=1 where id_sphynx=%s and id_amon=%s""" % (id_sphynx,id_amon)
445 return self.dbpool.runOperation(query).addCallbacks(lambda x : [1,content],db_client_failed)
446
448 """liste les configs vpn amon présentes pour un sphynx"""
449 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD)
450 cursor=cx.cursor()
451 query = """select id_amon,etat from conf_vpn where id_sphynx=%s order by etat,id_amon desc""" % id_sphynx
452 cursor.execute(query)
453 data=cursor.fetchall()
454 cursor.close()
455 cx.close()
456
457 liste_amons=[]
458 for ligne in data:
459 liste_amons.append([int(ligne[0]),int(ligne[1])])
460 return 1,liste_amons
461
463 """confirme la réception d'une archive par un serveur"""
464 try:
465 id_serveur = int(id_serveur)
466 serv = self.parent.s_pool.get(cred_user,id_serveur)
467 except KeyError, ValueError:
468 return 0,u("serveur inconnnu dans la base zephir")
469
470 serveur_dir = serv.get_confdir()
471 try:
472
473 os.unlink(serveur_dir+os.sep+archive+'.tar')
474
475 os.unlink(serveur_dir+os.sep+archive+'.md5')
476 except:
477 return 0, u("""erreur de suppression de l'archive""")
478 else:
479 return 1, u('ok')
480
482 """confirme la réception d'une archive par un serveur"""
483 try:
484 id_serveur = int(id_serveur)
485 serv = self.parent.s_pool.get(cred_user,id_serveur)
486 except KeyError, ValueError:
487 return 0,u("serveur inconnnu dans la base zephir")
488
489 serveur_dir = serv.get_confdir()
490
491 try:
492 fic_md5=open(serveur_dir+os.sep+archive+'.md5')
493 md5sum = fic_md5.readlines()
494 fic_md5.close()
495 except:
496 return 0, u("""fichier %s.md5 non trouve""" % (archive))
497 else:
498
499 return 1, base64.encodestring(md5sum[0])
500
502 """installation d'un module (récupération d'un dictionnaire)"""
503
504
505
506 query = """select id, libelle, version from modules where id=%s""" % id_module
507 return self.dbpool.runQuery(query).addCallbacks(self._install_module,db_client_failed,callbackArgs=[dico_b64])
508
510 if data == []:
511 return 0,u("""erreur, module non trouvé""")
512 else:
513 id_module = data[0][0]
514 libelle = data[0][1]
515 version = data[0][2]
516 if version == 1:
517
518 dico_path = os.path.abspath(config.ROOT_DIR)+os.sep+'dictionnaires'
519 dico_b64 = {'dico-'+str(libelle):dico_b64}
520 else:
521
522 dico_path = os.path.abspath(config.ROOT_DIR)+os.sep+'dictionnaires'+os.sep+str(libelle)
523
524 for dic_name, data in dico_b64.items():
525 dico = os.path.join(dico_path, dic_name)
526 try:
527 if os.path.isfile(dico):
528
529 os.unlink(dico)
530
531 fic_dico = open(dico,'w')
532 fic_dico.write(base64.decodestring(data))
533 fic_dico.close()
534 except:
535 return 0,u("erreur de mise a jour du dictionnaire du module")
536
537 return 1,u("ok")
538
539
541 """sauvegarde des fichiers de configuration d'un serveur"""
542 try:
543 id_serveur = int(id_serveur)
544 serv = self.parent.s_pool.get(cred_user, id_serveur)
545 except KeyError, ValueError:
546 return 0,u("serveur inconnnu dans la base zephir")
547 module = serv.id_mod
548 variante = serv.id_var
549 archive='fichiers_zephir'+str(id_serveur)
550 public_dir = '/var/spool/uucppublic'
551 temp_dir = public_dir+os.sep+str(id_serveur)
552
553
554 if os.path.isdir(temp_dir):
555 shutil.rmtree(temp_dir)
556 try:
557 os.mkdir(temp_dir)
558 except:
559 return 0,u("""erreur de creation du repertoire temporaire""")
560 serveur_dir = serv.get_confdir()
561
562 try:
563 fic_md5 = open(public_dir+os.sep+archive+'.md5','w')
564 fic_md5.write(checksum)
565 fic_md5.close()
566 except:
567 return 0, u("""erreur d'écriture du fichier de checksum""")
568 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir,archive)
569 res=os.system(cmd_md5)
570 if res != 0:
571 return 0,u("""archive corrompue""")
572 else:
573
574 cmd_tar = """cd %s ; tar -C %s --same-owner -xhpf %s.tar >/dev/null 2>&1""" % (public_dir,str(id_serveur),archive)
575 os.system(cmd_tar)
576
577
578 directories = ['dicos','fichiers_perso','patchs','fichiers_zephir']
579 for rep in directories:
580 try:
581 if rep == 'dicos' and os.path.isdir(os.path.join(os.path.abspath(config.PATH_MODULES),str(module),'dicos')):
582
583 shutil.rmtree(serveur_dir+os.sep+rep+'/local')
584 else:
585 shutil.rmtree(serveur_dir+os.sep+rep)
586 except:
587
588 pass
589
590 res = 0
591 for rep in directories:
592 if res == 0:
593 if os.path.isdir(os.path.join(os.path.abspath(config.PATH_MODULES),str(module),'dicos')) and rep == 'dicos':
594
595 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/'+rep+'/local', os.path.join(serveur_dir,rep)))
596 else:
597 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/'+rep,serveur_dir))
598 if res == 0:
599 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')
600
601 if res != 0:
602 return 0, u("""erreur de mise en place des fichiers""")
603
604
605 res = os.system("mv -f %s %s" % (temp_dir+'/temp_zephir/zephir.eol',serveur_dir))
606 if res != 0:
607 return 0, u("""erreur de mise en place de zephir.eol""")
608 else:
609
610 serv.maj_params({'config_ok':1})
611
612
613 serv.check_md5conf()
614
615 try:
616
617 os.unlink(public_dir+os.sep+archive+'.tar')
618 os.unlink(public_dir+os.sep+archive+'.md5')
619 shutil.rmtree(temp_dir)
620 except:
621 return 0, u("""erreur de supression des fichiers temporaires""")
622 return 1, u('ok')
623
624
626 """installation d'une variante pour un module"""
627 try:
628 id_serveur = int(id_serveur)
629 serv = self.parent.s_pool.get(cred_user, id_serveur)
630 except KeyError, ValueError:
631 return 0,u("serveur inconnnu dans la base zephir")
632 module = serv.id_mod
633 variante = serv.id_var
634 query="""select id,module,owner,passmd5 from variantes where id = %s and module = %s""" % (variante,module)
635 return self.dbpool.runQuery(query).addCallbacks(self._install_variante2,db_client_failed,callbackArgs=[cred_user,checksum,login,passwd_md5,serv.get_rne(),id_serveur])
636
637
639 """vérification de l'archive et stockage des fichiers"""
640 if data == []:
641 return 0, u("""variante non retrouvée dans la base""")
642 variante = data[0][0]
643 module = data[0][1]
644 owner_var = data[0][2]
645 passwd_var= data[0][3]
646 archive='variante'+str(id_serveur)
647 public_dir = '/var/spool/uucppublic'
648 temp_dir = public_dir+os.sep+str(id_serveur)
649 variante_dir = os.path.abspath(config.PATH_ZEPHIR)+os.sep+'modules'+os.sep+str(module)+os.sep+'variantes'+os.sep+str(variante)
650
651
652 if cred_user != owner_var:
653
654 if passwd_var not in [None,'']:
655
656 if passwd_md5 != passwd_var:
657 return 0,u("""erreur, le mot de passe est invalide""")
658
659
660
661 if os.path.isdir(temp_dir):
662 shutil.rmtree(temp_dir)
663 try:
664 os.mkdir(temp_dir)
665 except:
666 return 0,u("""erreur de création du repertoire temporaire""")
667
668 try:
669 fic_md5 = open(public_dir+os.sep+archive+'.md5','w')
670 fic_md5.write(checksum)
671 fic_md5.close()
672 except:
673 return 0, u("""erreur d'écriture du fichier de checksum""")
674 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir,archive)
675 res=os.system(cmd_md5)
676 if res != 0:
677 return 0,u("""archive corrompue""")
678 else:
679
680 cmd_tar = """cd %s ; tar -C %s --same-owner -xhpf %s.tar > /dev/null""" % (public_dir,str(id_serveur),archive)
681 os.system(cmd_tar)
682
683
684 try:
685 shutil.rmtree(variante_dir+os.sep+'dicos')
686 shutil.rmtree(variante_dir+os.sep+'patchs')
687 shutil.rmtree(variante_dir+os.sep+'fichiers_perso')
688 shutil.rmtree(variante_dir+os.sep+'fichiers_zephir')
689 except:
690 return 0, u("""erreur de supression de l'ancienne variante""")
691
692 res = os.system("mv %s %s" % (temp_dir+os.sep+'patch/variante',variante_dir+os.sep+'patchs'))
693 if res == 0:
694 res = os.system("mv %s %s" % (temp_dir+os.sep+'dicos/variante',variante_dir+os.sep+'dicos'))
695 if res == 0:
696 res = os.system("mv %s %s" % (temp_dir+os.sep+'fichiers_perso',variante_dir+os.sep+'fichiers_perso'))
697 if res == 0:
698 res = os.system("mv %s %s" % (temp_dir+os.sep+'fichiers_zephir',variante_dir+os.sep+'fichiers_zephir'))
699 if res != 0:
700 return 0, u("""erreur de mise en place de la variante""")
701
702 try:
703
704 os.unlink(public_dir+os.sep+archive+'.tar')
705 os.unlink(public_dir+os.sep+archive+'.md5')
706 shutil.rmtree(temp_dir)
707 except:
708 return 0, u("""erreur de supression des fichiers temporaires""")
709
710 if passwd_var in [None,'']:
711
712 query = """update variantes set owner ='%s', passmd5='%s' where id = %s and module = %s""" % (login,passwd_md5,variante,module)
713 return self.dbpool.runOperation(query).addCallbacks(lambda x : [1,'ok'],lambda x : [0,'erreur de stockage du mot de passe'])
714 else:
715 return 1,u('ok')
716
718 """ met à jour la table d'état du serveur pour une action précise
719 (ex: MAJ ou CONFIG) afin de refléter l'état de cohérence actuelle du serveur
720 """
721 params = {'last_log':str(date)}
722 if type_action in ['MAJ','CONFIGURE','RECONFIGURE','SAUVEGARDE','REBOOT','SERVICE_RESTART']:
723
724 if int(etat) == -1:
725 params['%s_ok' % type_action.lower()] = [2, str(date), msg]
726 elif int(etat) > 0:
727 params['%s_ok' % type_action.lower()] = [0, str(date), msg]
728 elif int(etat) == 0:
729 if type_action == "MAJ":
730
731 params['query_maj'] = [0, str(date)]
732 elif type_action == "CONFIGURE":
733
734
735
736 md5file = os.path.join(os.path.abspath(config.PATH_ZEPHIR),'data','config%s.md5' % id_serveur)
737 if os.path.isfile(md5file):
738 self.parent.s_pool.edit_serveur(id_serveur,{'md5s':1})
739 params['md5s'] = [1,""]
740 params['%s_ok' % type_action.lower()] = [1, str(date), msg]
741 elif type_action == 'LOCK':
742 if int(etat) == 1:
743 params['lock_ok'] = [2, str(date), msg]
744 else:
745 params['lock_ok'] = [1,'']
746 elif type_action == 'QUERY-MAJ':
747 if int(etat) == 0:
748 if 'paquets' in msg:
749 try:
750 nb_paquets = int(msg.split()[0])
751 params['query_maj'] = [nb_paquets,str(date)]
752 except:
753 params['query_maj'] = [-2,'erreur de lecture du résultat']
754 else:
755 params['query_maj'] = [0, str(date)]
756 elif int(etat) > 0:
757 params['query_maj'] = [-1, str(msg)]
758 try:
759 id_serveur = int(id_serveur)
760 serv = self.parent.s_pool[id_serveur]
761 except KeyError, ValueError:
762 return 0,u("serveur inconnnu dans la base zephir")
763 else:
764
765 self.parent.s_pool.update_contact(id_serveur)
766
767
768 query = """select id,etat,date,type from last_log_serveur where id_serveur=%s and type='%s'""" %(id_serveur,type_action.replace("'","\\\'"))
769 return self.dbpool.runQuery(query).addCallbacks(self._log_serveur,db_client_failed,callbackArgs=[id_serveur,type_action,date,int(etat),msg, params, serv])
770
771 - def _log_serveur(self,data,id_serveur,type_action,date,etat,msg,params,serv):
772
773 if data != []:
774
775 last_date = data[0][2]
776 new_date = datetime.strptime(str(date), "%c")
777 if new_date >= last_date:
778 query = """update last_log_serveur set id_serveur=%s,date='%s',type='%s',message='%s',etat=%s where id=%s""" % \
779 (int(id_serveur),date,type_action.replace("'","\\\'"),msg.replace("'","\\\'"),etat,data[0][0])
780
781 if params.has_key('query_maj'):
782 self.parent.s_pool.edit_serveur(id_serveur,{'maj':params['query_maj'][0]})
783 serv.maj_params(params)
784 else:
785
786 return self._log_serveur2(None,id_serveur,type_action,date,etat,msg)
787 else:
788 query = """insert into last_log_serveur (id_serveur,date,type,message,etat) values (%s,'%s','%s','%s',%s)""" % (int(id_serveur),date,type_action.replace("'","\\\'"),msg.replace("'","\\\'"),etat)
789 return self.dbpool.runOperation(query).addCallbacks(self._log_serveur2,db_client_failed,callbackArgs=[id_serveur,type_action,date,etat,msg])
790
791 - def _log_serveur2(self,data,id_serveur,type_action,date,etat,msg):
792 query = """insert into log_serveur (id_serveur,date,type,message,etat) values (%s,'%s','%s','%s',%s)""" % (int(id_serveur),date,type_action.replace("'","\\\'"),msg.replace("'","\\\'"),etat)
793
794 return self.dbpool.runOperation(query).addCallbacks(lambda x : [1,'ok'],db_client_failed)
795
797 """prépare la suppression des verrous sur un groupe"""
798 erreurs=[]
799 for serveur in liste:
800 retour = self.xmlrpc_release_lock(cred_user, serveur['id'])
801 if retour[0] == 0:
802 erreurs.append(str(serveur['id'])+' : '+retour[1])
803 if erreurs != []:
804 return 0,u(erreurs)
805 else:
806 return 1, u('ok')
807
809 """demande la libération des verrous sur un serveur"""
810 try:
811 id_serveur = int(id_serveur)
812 serv = self.parent.s_pool.get(cred_user,id_serveur)
813 except KeyError, ValueError:
814 return 0,u("serveur inconnnu dans la base zephir")
815 else:
816 serv.maj_params({'del_locks':True})
817 return 1, 'ok'
818
820 """indique si les locks doivent être ignorés
821 @params unlocked: si True, on enlève l'attibut del_lock de params"""
822 try:
823 id_serveur = int(id_serveur)
824 serv = self.parent.s_pool.get(cred_user,id_serveur)
825 except KeyError, ValueError:
826 return 0,u("serveur inconnnu dans la base zephir")
827 params = serv.get_params()
828 if params.has_key('del_locks'):
829 if params['del_locks'] == True:
830 if unlocked:
831
832 serv.maj_params({'del_locks':False})
833
834 return 1, True
835 return 1, False
836
838 """envoi d'un message d'alerte à une liste d'adresses mail
839 """
840 bad_addr={}
841 mail_content = "Subject: [Zephir] %s\n\n%s" % (subject,msg)
842 mail_client=smtplib.SMTP()
843 try:
844 smtplib.socket.setdefaulttimeout(3)
845 if config.MAIL_PORT != '':
846 mail_client.connect(config.MAIL_ADRESSE,config.MAIL_PORT)
847 else:
848 mail_client.connect(config.MAIL_ADRESSE)
849 except:
850 return 0, u('erreur de connexion au serveur smtp')
851 else:
852 try:
853 bad_addr = mail_client.sendmail(config.MAIL_ACCOUNT,adresses,mail_content)
854 except:
855 return 0, u("erreur d'envoi du mail d'alerte")
856 return 1, bad_addr
857
858
860 """vérifie l'archive envoyée par le serveur et met le site et les données xml en place
861 """
862 log.msg ("connexion du serveur %s" % str(id_serveur))
863
864 cx = PgSQL.connect(database=config.DB_NAME,user=config.DB_USER,password=config.DB_PASSWD)
865 query="""select type,etat from last_log_serveur where id_serveur=%s and type='LOCK' order by date desc,id desc""" % id_serveur
866 cursor=cx.cursor()
867 cursor.execute(query)
868 data=cursor.fetchall()
869 cursor.close()
870 cx.close()
871 etat=0
872 if data != []:
873 etat=int(data[0][1])
874 if etat == 1:
875
876 self.xmlrpc_log_serveur(cred_user,id_serveur,str(time.ctime()),'LOCK','0',"""Reprise de l'activité uucp""")
877
878 self.parent.s_pool.update_contact(id_serveur)
879
880 public_dir = '/var/spool/uucppublic'
881 archive = 'site%s' % id_serveur
882 try:
883 fic_md5 = open(public_dir+os.sep+archive+'.md5','w')
884 fic_md5.writelines(checksum)
885 fic_md5.close()
886 except:
887 return 0, u("""erreur d'écriture du fichier de checksum""")
888 cmd_md5 = """cd %s ; md5sum -c %s.md5 2>&1 > /dev/null""" % (public_dir, archive)
889 res=os.system(cmd_md5)
890 if res != 0:
891 return 0,u("""archive corrompue""")
892 else:
893 compressed=''
894
895 if int(new_agents) == 1:
896
897 compressed = 'z'
898 rep_dest = os.path.abspath(config.PATH_ZEPHIR)
899
900 try:
901 shutil.rmtree(rep_dest+os.sep+"data"+os.sep+str(id_serveur))
902 except:
903 pass
904 else:
905 rep_dest = os.path.abspath(config.PATH_ZEPHIR)+os.sep+"sites"+os.sep+str(id_serveur)
906
907 if os.path.exists(rep_dest):
908 shutil.rmtree(rep_dest)
909 os.makedirs(rep_dest)
910
911 cmd_tar = """cd %s ; /bin/tar -C %s -x%sf %s.tar 2> /dev/null""" % (public_dir, rep_dest, compressed, archive)
912 res=os.system(cmd_tar)
913 if res != 0:
914 return 0,u("erreur de mise en place du site sur zephir")
915 serv = self.parent.s_pool[int(id_serveur)]
916 serv.check_md5conf()
917
918 if serv.version == 'creole1':
919 f_site = file(os.path.join(rep_dest,'data',str(id_serveur),'site.cfg'))
920 data = f_site.read()
921 f_site.close()
922 try:
923 data = unicode(data,'ISO-8859-1').encode(config.charset)
924 except:
925 pass
926 else:
927 f_site = file(os.path.join(rep_dest,'data',str(id_serveur),'site.cfg'),'w')
928 f_site.write(data)
929 f_site.close()
930 for xml_file in glob.glob(os.path.join(rep_dest,'data',str(id_serveur),'*/agent.xml')):
931 try:
932 xml = file(xml_file).read()
933
934 for ori, dst in config.xml_table.items():
935 xml = xml.replace(ori,dst)
936 file(xml_file,'w').write(xml)
937 except:
938 print "erreur lors de la conversion de %s en %s" % (xml_file, config.charset)
939
940
941
942 try:
943 if self.agent_manager.has_key(str(id_serveur)):
944
945
946 self.agent_manager[str(id_serveur)].update_structure()
947 stats = self.agent_manager[str(id_serveur)].get_measure()
948 result_ag = self.agent_manager[str(id_serveur)].global_status()
949 else:
950
951
952 AgentCollecteur(id_serveur)
953 result_ag = ServeurStatus(id_serveur).get_status()
954 except:
955 traceback.print_exc()
956 result_ag = 1
957
958
959 try:
960 result_zeph = self.parent.getSubHandler('serveurs').xmlrpc_get_status(cred_user,id_serveur)
961 except:
962 return 0, u("erreur de récupération de l'état zephir du serveur %s" % id_serveur)
963
964 d = defer.Deferred()
965 d.addCallback(self._alerte,result_zeph[1],result_ag)
966 d.callback(id_serveur)
967
968 return 1,u("ok")
969
970
971 - def _alerte(self,id_serveur,etat_zeph,etat_ag):
972 """vérification de l'état du serveur et envoi mail si nécessaire
973 """
974
975 query="select serveurs.id,serveurs.rne,installateur,serveurs.libelle,modules.libelle,etablissements.libelle,serveurs.etat,serveurs.params \
976 from serveurs,etablissements,modules \
977 where serveurs.id=%s and etablissements.rne=serveurs.rne and modules.id=module_actuel" % id_serveur
978 self.dbpool.runQuery(query).addCallbacks(self._alerte2,db_client_failed,callbackArgs=[etat_zeph,etat_ag])
979
980 - def _alerte2(self,data,etat_zeph,etat_ag):
981
982 if data == []:
983
984 pass
985 else:
986 id_serveur = data[0][0]
987 rne = data[0][1]
988 libelle = data[0][3]
989 module = data[0][4]
990 libel_etab = data[0][5]
991 etat_precedent = data[0][6]
992 if etat_precedent != None:
993 try:
994 etat_precedent = int(etat_precedent)
995 except Exception, e:
996 etat_precedent = 1
997 erreur = 0
998 msg = """le serveur %s (%s - %s)\n établissement : %s (%s)""" % (libelle, id_serveur, module, rne, libel_etab)
999
1000 for cle in etat_zeph.keys():
1001 etat = etat_zeph[cle]
1002 if type(etat) == list:
1003 if len(etat) == 3:
1004 if etat[0] == 0:
1005 if erreur == 0:
1006 msg += """\n(se reporter à la page d'état du serveur dans l'application web)"""
1007 erreur = 1
1008 msg +="""\n\nlog du %s : %s""" % (etat[1].encode(config.charset),etat[2].encode(config.charset))
1009 if (cle == 'lock_ok') and (etat[0] != 1):
1010 msg += """\n\n Fonction Zephir verouillées, connectez vous sur le serveur pour vérifier son état
1011 (commande '/usr/share/zephir/scripts/zephir_client del_lock' pour dévérouiller)"""
1012
1013
1014 serv = self.parent.s_pool[id_serveur]
1015 try:
1016 params=eval(data[0][7])
1017 assert type(params) == dict
1018 params['agents'] = etat_ag
1019 except:
1020
1021 params={'agents':etat_ag}
1022 serv.maj_params(params)
1023
1024 if etat_ag == 0:
1025 erreur = 2
1026
1027 msg+="""\n\nerreur remontée par le serveur (cf. https://%s:%s/agents/%s)""" % (config.ADRESSE_ZEPHIR,config.PORT_HTTP,id_serveur)
1028
1029
1030 if erreur != 0:
1031 if etat_precedent not in [0,4]:
1032 if etat_precedent == 3:
1033 serv.set_status(4)
1034 else:
1035 serv.set_status(0)
1036
1037 if etat_precedent == 2:
1038
1039 subject = "problème détecté à la reprise de contact: serveur %s (%s)" % (libelle,rne)
1040 else:
1041 subject = "problème détecté : serveur %s (%s)" % (libelle,rne)
1042 msg = "\nproblème détecté sur " + msg
1043 self._send_alerte("problème détecté : serveur ",{int(id_serveur):msg})
1044 else:
1045
1046
1047 if etat_precedent in [0,4]:
1048 if etat_precedent == 4:
1049 serv.set_status(3)
1050 else:
1051 serv.set_status(1)
1052
1053 subject = "fin d'alerte : serveur %s (%s)" % (libelle,rne)
1054 msg = "\n fin d'alerte pour " + msg
1055 self._send_alerte("fin d'alerte : ",{int(id_serveur):msg})
1056
1057 if etat_precedent == None:
1058 serv.set_status(1)
1059
1061 """recherche les mails et sms des personnes surveillant un serveur particulier
1062 """
1063 if msgs != {}:
1064 query = """select id,serveurs from groupes_serveurs"""
1065 self.dbpool.runQuery(query).addCallbacks(self._send_alerte2,db_client_failed,callbackArgs=[subject,msgs])
1066
1068
1069
1070 groupes=[]
1071 for id_serveur in msg.keys():
1072 for groupe in data:
1073 if id_serveur in eval(groupe[1]):
1074 if groupe[0] not in groupes:
1075 groupes.append(groupe[0])
1076 query = """select groupes,mail,sms,mail_actif,sms_actif from users \
1077 where groupes != '' and (mail_actif=1 or sms_actif=1)"""
1078 self.dbpool.runQuery(query).addCallbacks(self._send_alerte3,db_client_failed,callbackArgs=[groupes,subject,msg])
1079
1081 """regarde quels utilisateurs surveillent les groupes
1082 en question et envoie un mail ou sms si besoin
1083 """
1084
1085 destinataires = []
1086 for user in data:
1087 try:
1088 groupes_user=eval(user[0])
1089 except:
1090 groupes_user=[]
1091 for groupe in groupes_user:
1092
1093 if groupe in groupes:
1094
1095 if user[3]==1:
1096
1097 for adresse in user[1].split(','):
1098 r=re.match("""^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9]+)*$""",adresse)
1099 if r is not None:
1100
1101 if adresse not in destinataires:
1102 destinataires.append(adresse)
1103
1104 if destinataires != []:
1105 self._sendmail(destinataires,subject + str(msg.keys()),"\n".join(msg.values()))
1106
1108 """vérifie toutes les x minutes si des serveurs ont dépassé leur timeout.
1109 vérification toutes les 5 miuntes par défaut"""
1110
1111 try:
1112
1113 if self.start_time is not None:
1114 query = "update serveurs set last_contact = '%s' where last_contact is not null and etat <> 2" % self.start_time
1115 self.dbpool.runOperation(query).addCallbacks(lambda x : [1, "OK"],db_client_failed)
1116 reactor.callLater(5, self._scan_timeouts)
1117 self.start_time = None
1118 except:
1119 return 0, "erreur de démarrage de la boucle de surveillance"
1120 return 1,""
1121
1123 reactor.callLater(self.scan_delay,self._scan_timeouts)
1124 query = """select serveurs.id,timeout,last_contact,serveurs.libelle, \
1125 serveurs.rne,etablissements.libelle,modules.libelle,serveurs.etat \
1126 from serveurs,etablissements,modules where timeout > 0 and last_contact is not null and \
1127 serveurs.rne=etablissements.rne and module_actuel=modules.id"""
1128 self.dbpool.runQuery(query).addCallbacks(self._scan_timeouts2,db_client_failed)
1129
1131 """vérifie si le dernier contact est moins ancien que le timeout du serveur.
1132 """
1133 erreurs={}
1134 reprises={}
1135 bloquages={}
1136 debloquages={}
1137 cmds=uucp_pool._scan_pool()
1138 for serveur in data:
1139
1140 serv = self.parent.s_pool[int(serveur[0])]
1141 params = {'timeout':[-2, ""]}
1142 last = float(serveur[2])
1143 delta = float(time.time()) - last
1144 try:
1145 etat_actuel = int(serveur[7])
1146 except:
1147 etat_actuel = 1
1148
1149 try:
1150 timeout = int(serveur[1])
1151 except:
1152 pass
1153 else:
1154 params['timeout'] = [1, time.ctime(last)]
1155
1156
1157 max_delay = int(timeout) * 2 + 240
1158 if ( delta > max_delay ) and timeout != 0:
1159 params['timeout'][0]=0
1160 if etat_actuel != 2:
1161
1162 log.msg("timeout du serveur %s" % serveur[0])
1163 serv.set_status(2)
1164
1165 subject = """perte du contact : serveur(s) %s (%s)""" % (serveur[3],serveur[4])
1166 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))
1167
1168 erreurs[serveur[0]]=msg
1169 else:
1170 if etat_actuel == 2:
1171
1172 serv.set_status(1)
1173 subject = """reprise du contact : serveur(s) %s (%s)""" % (serveur[3],serveur[4])
1174 msg = """reprise du contact avec le serveur n°%s - %s (%s) de l'établissement %s (%s) : %s""" % \
1175 (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5],time.ctime(last))
1176 reprises[serveur[0]]=msg
1177
1178
1179 id_uucp = serveur[4]+"-"+str(serveur[0])
1180 old_cmds = uucp_pool.check_timeout(max_delay, id_uucp)
1181 if old_cmds != {}:
1182 if etat_actuel not in [3,4]:
1183
1184 msg = """commandes bloquées en attente pour le serveur n°%s - %s (%s) de l'établissement %s (%s)
1185 Vous pouvez afficher les logs de transfert UUCP sur ce serveur à l'aide de la commande uulog"""
1186 bloquages[serveur[0]] = msg % (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5])
1187 if etat_actuel == 0:
1188
1189 serv.set_status(4)
1190 else:
1191
1192 serv.set_status(3)
1193 else:
1194 if etat_actuel in [3,4]:
1195
1196 msg = """débloquage des commandes (reprise d'activité uucp) pour le serveur n°%s - %s (%s) de l'établissement %s (%s)"""
1197 debloquages[serveur[0]] = msg % (serveur[0],serveur[3],serveur[6],serveur[4],serveur[5])
1198 if etat_actuel == 4:
1199
1200 serv.set_status(0)
1201 else:
1202
1203 serv.set_status(1)
1204
1205
1206 serv.maj_params(params)
1207
1208 self._send_alerte("commandes non lancées : ",bloquages)
1209 self._send_alerte("commandes débloquées : ",debloquages)
1210 self._send_alerte("perte de contact : ",erreurs)
1211 self._send_alerte("reprise du contact : ",reprises)
1212
1214 """retourne la liste des actions uucp en attente"""
1215
1216 try:
1217 id_serveur = int(id_serveur)
1218 serv = self.parent.s_pool.get(cred_user, id_serveur)
1219 except KeyError, ValueError:
1220 return 0,u("serveur inconnnu dans la base zephir")
1221 else:
1222 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
1223
1224 cmds=uucp_pool._scan_pool()
1225
1226 try:
1227 cmds=uucp_pool.list_cmd(id_uucp)[id_uucp]
1228 except:
1229 cmds={}
1230 try:
1231 files=uucp_pool.list_files(id_uucp)[id_uucp]
1232 except:
1233 files={}
1234 return 1,u([cmds,files])
1235
1237 """indique à un serveur si il doit ou non effectuer des actions
1238 """
1239
1240 try:
1241 id_serveur = int(id_serveur)
1242 serv = self.parent.s_pool.get(cred_user, id_serveur)
1243 except KeyError, ValueError:
1244 return 0,u("serveur inconnnu dans la base zephir")
1245 else:
1246 id_uucp = str(serv.get_rne()) + '-' + str(id_serveur)
1247
1248 cmds=uucp_pool._scan_pool()
1249 if len(uucp_pool.pool[id_uucp]) > 0:
1250 return 1, True
1251 else:
1252 return 1, False
1253
1255 """annule toutes les actions en attente sur un/plusieurs serveur(s)"""
1256
1257 try:
1258 for id_serveur in serveurs:
1259 id_serveur = int(id_serveur)
1260 assert self.parent.s_pool.has_key(id_serveur)
1261 except KeyError, ValueError:
1262 return 0,u("serveur inconnnu dans la base zephir")
1263 else:
1264 for id_serveur in serveurs:
1265 rne = self.parent.s_pool.get(cred_user,int(id_serveur)).get_rne()
1266 id_uucp = str(rne) + '-' + str(id_serveur)
1267
1268 if id_tache is None:
1269 try:
1270 uucp_pool.flush([id_uucp])
1271 except UUCPError, e:
1272 return 0, u("erreur de purge des commandes : %" % str(e))
1273 else:
1274 try:
1275 if str(uucp_pool.pool[id_uucp][int(id_tache)][1]) == COMMANDS["zephir_client configure"]:
1276
1277
1278 if str(uucp_pool.pool[id_uucp][int(id_tache)-1][0]) == "transfert":
1279 uucp_pool.remove_cmd(id_uucp,int(id_tache)-1)
1280 uucp_pool.remove_cmd(id_uucp,int(id_tache))
1281 except UUCPError, e:
1282 return 0,u("Erreur de supression de la commande uucp : %" %str(e))
1283 except KeyError:
1284 pass
1285
1286 return 1,"OK"
1287