Package zephir :: Package utils :: Module uucp_utils
[frames] | no frames]

Source Code for Module zephir.utils.uucp_utils

  1  #! /usr/bin/env python 
  2  # -*- coding: UTF-8 -*- 
  3  ########################################################################### 
  4  # Eole NG - 2007   
  5  # Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon) 
  6  # Licence CeCill  cf /root/LicenceEole.txt 
  7  # eole@ac-dijon.fr  
  8  #   
  9  # uucp_utils.py 
 10  #   
 11  # fonctions utilitaires pour la gestion d'uucp 
 12  #        
 13  ########################################################################### 
 14   
 15  import os,time,shutil,tempfile 
 16   
 17  UUCP_DIR = "/var/spool/uucp" 
 18  CMD_UUX = "/usr/bin/uux2" 
 19  CMD_UUCP = "/usr/bin/uucp2" 
 20  LOG_FILE = "/tmp/rapport.zephir" 
 21  LOCK = "/var/spool/uucp/lock" 
 22  IGNORE_LIST = ['.ssh','.Status','.Temp','.Received','.bash_history','dead.letter'] 
 23   
 24  COMMANDS = {"zephir_client save_files":"Sauvegarde complète", 
 25              "zephir_client save_files 0":"Sauvegarde (complète)", 
 26              "zephir_client save_files 1":"Sauvegarde (configuration)", 
 27              "zephir_client save_files 2":"Sauvegarde (configuration/patchs/dicos)", 
 28              "zephir_client save_files 3":"Sauvegarde (fichiers divers)", 
 29              "zephir_client maj_auto":"Mise à jour", 
 30              "zephir_client maj_auto E":"Mise à jour complète", 
 31              "zephir_client maj_client":"Mise à jour de zephir-client", 
 32              "zephir_client download_upgrade":"Préchargement des paquets (Upgrade-Auto)", 
 33              "zephir_client configure":"Envoi de configuration", 
 34              "zephir_client reboot":"Redémarrage du serveur", 
 35              "zephir_client service_restart":"Redémarrage du service", 
 36              "zephir_client reconfigure":"Reconfiguration", 
 37              "zephir_client update_key regen_certs":"Renouvellement des clés d'enregistrement et certificats ssl", 
 38              "zephir_client update_key":"Renouvellement des clés d'enregistrement", 
 39              "zephir_client change_ip":"Préparation au changement d'adresse de zephir", 
 40              "zephir_client purge_ip":"Annulation du changement d'adresse de zephir",} 
 41   
 42  UUCPError = 'UUCPError' 
 43       
 44   
 45  NUMBERS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] 
 46   
 47  # fonction de conversion  
48 -def convert_num(chaine):
49 result=0 50 digits = range(len(chaine)) 51 # on parcourt la chaine en partant de la fin 52 digits.reverse() 53 for i in range(len(chaine)): 54 # valeur du digit en cours 55 digit = NUMBERS.index(chaine[digits[i]]) 56 # valeur * longueur_base^position 57 result = result + digit * len(NUMBERS).__pow__(i) 58 return result
59
60 -class UUCP:
61 """wrapper d'uucp pour permettre la gestion des files dans zephir""" 62
63 - def __init__(self,peers=None):
64 """initialisation de l'objet""" 65 self.peers_ori=peers 66 self.pool={} 67 self._scan_pool()
68
69 - def _scan_pool(self, peer=None):
70 """crée la liste d'attente en mémoire""" 71 # on crée la liste des commandes et transferts actuels 72 # si pas de noms de machines spécifiées, on recherche dans tous les systèmes 73 if peer is not None: 74 peers = [peer] 75 else: 76 if self.peers_ori is None: 77 peers = os.listdir(UUCP_DIR) 78 for peer in IGNORE_LIST: 79 if peer in peers: 80 peers.remove(peer) 81 else: 82 peers = self.peers_ori 83 # parcours de /var/spool/uucp 84 for peer in peers: 85 # répertoire uucp de ce correspondant 86 peer_dir = os.path.abspath(UUCP_DIR+os.sep+peer) 87 # liste des actions en attente 88 lst={} 89 if os.path.isdir(peer_dir+"/C."): 90 for fic in os.listdir(peer_dir+"/C."): 91 # on récupère la date de création de la commande (timestamp) 92 date_creat = os.stat(peer_dir+"/C./"+fic)[-1] 93 f=file(peer_dir+"/C./"+fic) 94 l=f.read().strip().split('\n')[0] 95 f.close() 96 # séparation des paramètres 97 # ex de lignes: 98 # S /var/lib/zephir/conf/0210056X/4/config-zephir.tar ~ root -Cd D.0008 0644 99 # S D.X0007 X.zephirN0007 root -C D.X0007 0666 100 args=l.split()[1] 101 script=l.split()[5] 102 seq_number=convert_num(script[-4:]) 103 # si on a une commande 104 type_cmd = "transfert" 105 if args.startswith("D.X"): 106 type_cmd = "execute" 107 # on regarde laquelle dans le fichier correspondant 108 f=file(peer_dir+"/D.X/"+script) 109 l=f.read().strip().split('\n') 110 f.close() 111 for line in l: 112 line = line.strip() 113 if line[:2] == "C ": 114 args = line[2:] 115 # on regarde si c'est une commande connue 116 cmds = COMMANDS.keys() 117 cmds.sort(reverse=True) 118 for cmd in cmds: 119 if line[2:].startswith(cmd): 120 args = line[2:].replace(cmd, COMMANDS[cmd]) 121 break 122 123 lst[seq_number]=(type_cmd,args,script,fic,date_creat) 124 125 self.pool[peer]=lst
126 127
128 - def add_cmd(self,peer,commande):
129 """met en place une commande distante""" 130 peer_dir = os.path.abspath(UUCP_DIR+os.sep+peer) 131 # on regarde si on a le droit d'écrire 132 timeout = 0 133 while os.path.isfile(LOCK): 134 # si non on attend la libération des ressources 135 timeout += 1 136 # si plus de 5 secondes d'attente, il y a surement un problème 137 if timeout > 10: 138 # print "Problème d'accès concurrent, fichier %s présent" % LOCK 139 raise UUCPError, "Problème d'accès concurrent, fichier %s présent" % LOCK 140 time.sleep(0.5) 141 # on bloque les autres appels à cette fonction en cas de 142 # demandes simultanées 143 lock=file(LOCK,"w") 144 lock.close() 145 # on recherche le grade à affecter à la commande (pour assurer l'ordre d'execution) 146 self._scan_pool(peer) 147 used_grades = [] 148 if peer in self.pool: 149 cmd_files = [uucmd[3] for uucmd in self.pool[peer].values()] 150 for uucmd in cmd_files: 151 cmd_grade = convert_num(uucmd[2]) 152 if cmd_grade not in used_grades: 153 used_grades.append(cmd_grade) 154 if used_grades != []: 155 new_grade = max(used_grades) + 1 156 else: 157 # grade de départ pour les commandes : 'O' (les transferts de fichiers ont 'N' par défaut) 158 new_grade = 24 159 # si on est déjà au grade maximum, on le conserve (ne devrait pas arriver sauf si file d'attente bloquée longtemps ?) 160 if new_grade >= len(NUMBERS): 161 new_grade = NUMBERS[-1] 162 else: 163 new_grade = NUMBERS[new_grade] 164 # construction de l'appel à uux 165 cmd = "%s -g %s -r '%s!%s >%s!%s'" % (CMD_UUX,new_grade,peer,commande,peer,LOG_FILE) 166 try: 167 # appel systeme 168 res=os.system(cmd) 169 # on ajoute la commande à la liste des commandes de ce peer 170 if res == 0: 171 # recherche du fichier correspondant (dernier fichier créé dans "C.") 172 tempbuf=tempfile.mktemp() 173 os.system("/bin/ls -t %s" % peer_dir+"/C./ > %s" % tempbuf) 174 output=file(tempbuf) 175 res2=output.read() 176 output.close() 177 os.unlink(tempbuf) 178 # on récupère le nom du fichier le plus récent 179 filename = res2.split()[0] 180 # nom du script correspondant 181 f=file(peer_dir+"/C./"+filename) 182 l=f.read().strip().split('\n')[0] 183 f.close() 184 script = l.split()[5] 185 # on déduit le n° dans la file à partir du nom de script 186 seq_num=convert_num(script[-4:]) 187 if not self.pool.has_key(peer): 188 self.pool[peer]={} 189 self.pool[peer][seq_num]=("execute",commande,script,filename) 190 # on libère la ressource 191 os.unlink(LOCK) 192 return seq_num 193 else: 194 os.unlink(LOCK) 195 raise Exception("uux2 a retourné une erreur") 196 except Exception,e: 197 os.unlink(LOCK) 198 # print """erreur lors de la préparation de l'exécution de %s : %s""" % (commande,e) 199 raise UUCPError, """erreur lors de la préparation de l'exécution de %s : %s""" % (commande,str(e))
200
201 - def add_file(self,peer,fichier,destination="~"):
202 """prépare l'envoi d'un fichier""" 203 peer_dir = os.path.abspath(UUCP_DIR+os.sep+peer) 204 # construction de l'appel à uucp 205 cmd = "%s -r %s %s\\!%s" % (CMD_UUCP,fichier,peer,destination) 206 # on regarde si on a le droit d'écrire 207 timeout = 0 208 while os.path.isfile(LOCK): 209 # si non on attend la libération des ressources 210 timeout += 1 211 # si plus de 5 secondes d'attente, il y a surement un problème 212 if timeout > 10: 213 # print "Problème d'accès concurrent, fichier %s présent" % LOCK 214 raise UUCPError, "Problème d'accès concurrent, fichier %s présent" % LOCK 215 time.sleep(0.5) 216 # on bloque les autres appels à cette fonction en cas de 217 # demandes simultanées 218 lock=file(LOCK,"w") 219 lock.close() 220 try: 221 # appel systeme 222 res=os.system(cmd) 223 # on ajoute le transfert à la liste des transferts de ce peer 224 if res == 0: 225 # recherche du fichier correspondant 226 tempbuf=tempfile.mktemp() 227 os.system("/bin/ls -t %s" % peer_dir+"/C./ > %s" % tempbuf) 228 output=file(tempbuf) 229 res2=output.read() 230 output.close() 231 os.unlink(tempbuf) 232 # on récupère le nom du fichier le plus récent 233 filename = res2.split()[0] 234 # nom du script correspondant 235 f=file(peer_dir+"/C./"+filename) 236 l=f.read().strip().split('\n')[0] 237 f.close() 238 script = l.split()[5] 239 # on déduit le n° dans la file à partir du nom de script 240 seq_num=convert_num(script[-4:]) 241 if not self.pool.has_key(peer): 242 self.pool[peer]={} 243 self.pool[peer][seq_num]=("transfert",fichier,script,filename) 244 # on libère la ressource 245 os.unlink(LOCK) 246 return 0 247 else: 248 os.unlink(LOCK) 249 raise UUCPError, """echec à l'exécution de uucp""" 250 except Exception,e: 251 os.unlink(LOCK) 252 raise UUCPError, """erreur lors de la préparation du transfert de %s : %s""" % (fichier,e)
253
254 - def _create_liste(self,type_cmd,peers):
255 """fonction interne qui liste les actions d'un type particulier""" 256 cmds = {} 257 # pour chaque peer 258 for peer in peers: 259 cmds[peer] = [] 260 if not self.pool.has_key(peer): 261 continue 262 # on parcourt la liste des actions en attente 263 numeros = self.pool[peer].keys() 264 numeros.sort() 265 for n in numeros: 266 action=self.pool[peer][n] 267 # si c'est une commande distante 268 if action[0] == type_cmd: 269 # on l'ajoute à la liste 270 cmds[peer].append((n,action[1])) 271 return cmds
272
273 - def check_timeout(self,max_time,peer=None):
274 """vérifie si il existe des commandes plus anciennes 275 que max_time pour un serveur donné (ou tous) 276 @param max_time: age maximum en seconde accepté pour une commande 277 retourne un dictionnaire {serveur:liste des ids de commande trop anciens}""" 278 dic_res = {} 279 if peer is not None: 280 peers=[peer] 281 else: 282 self._scan_pool() 283 peers=self.pool.keys() 284 for serveur in peers: 285 timeouts = [] 286 if self.pool.has_key(serveur): 287 for seq_num, data in self.pool[serveur].items(): 288 test_time = time.localtime(float(data[-1] + max_time)) 289 # si timeout (date de création + délai > date actuelle) 290 if test_time < time.localtime(): 291 # on renvoie le n° de commande et sa date de création 292 timeouts.append((seq_num, time.ctime(data[-1]))) 293 if timeouts != []: 294 dic_res[serveur] = timeouts 295 return dic_res
296
297 - def list_cmd(self,peer=None):
298 """renvoie la liste des commandes en attente""" 299 if peer is not None: 300 peers=[peer] 301 else: 302 self._scan_pool() 303 peers=self.pool.keys() 304 return self._create_liste("execute",peers)
305
306 - def list_files(self,peer=None):
307 """renvoie la liste des transferts en attente""" 308 if peer is not None: 309 peers=[peer] 310 else: 311 self._scan_pool() 312 peers=self.pool.keys() 313 return self._create_liste("transfert",peers)
314
315 - def remove_cmd(self,peer,num_cmd):
316 """supprime une commande ou un transfert""" 317 type_cmd,fichier,script,filename,date_creat = self.pool[peer][int(num_cmd)] 318 peer_dir = os.path.abspath(UUCP_DIR+os.sep+peer) 319 # on regarde si on a le droit d'écrire 320 timeout = 0 321 while os.path.isfile(LOCK): 322 # si non on attend la libération des ressources 323 timeout += 1 324 # si plus de 5 secondes d'attente, il y a surement un problème 325 if timeout > 10: 326 # print "Problème d'accès concurrent, fichier %s présent" % LOCK 327 raise UUCPError, "Problème d'accès concurrent, fichier %s présent" % LOCK 328 time.sleep(0.5) 329 # on bloque les autres appels à cette fonction en cas de 330 # demandes simultanées 331 lock=file(LOCK,"w") 332 lock.close() 333 # supression du fichier correspondant dans C. 334 try: 335 os.unlink(peer_dir+'/C./'+filename) 336 if type_cmd == "transfert": 337 # supression de la copie du fichier dans D. 338 os.unlink(peer_dir+'/D./'+script) 339 else: 340 # supression du script correspondant dans D.X 341 os.unlink(peer_dir+'/D.X/'+script) 342 # on libère la ressource 343 os.unlink(LOCK) 344 except: 345 # print "erreur lors de la suppression des fichiers" 346 os.unlink(LOCK) 347 raise UUCPError, "erreur lors de la suppression des fichiers" 348 349 del(self.pool[peer][int(num_cmd)]) 350 return 0
351 352
353 - def flush(self,peers=None):
354 """supprime toute la file d'attente""" 355 if peers is None: 356 for i in os.listdir(UUCP_DIR): 357 if i not in IGNORE_LIST: 358 try: 359 # on supprime le répertoire d'échange 360 if os.path.isdir(UUCP_DIR+os.sep+i): 361 shutil.rmtree(UUCP_DIR+os.sep+i) 362 self.pool[i]={} 363 except: 364 raise UUCPError, """erreur de suppression de la file d'attente de %s""" % i 365 else: 366 try: 367 for peer in peers: 368 if os.path.isdir(UUCP_DIR+os.sep+peer): 369 shutil.rmtree(UUCP_DIR+os.sep+peer) 370 self.pool[peer]={} 371 except: 372 raise UUCPError, """erreur de supression de la file d'attente""" 373 return 0
374 375 uucp_pool = UUCP() 376 377 if __name__ == '__main__': 378 peers = ["0210056X-1","0210056X-2","0210056X-3","0210056X-4","0210056X-5"] 379 uucp=UUCP(peers) 380 peer = "" 381 while not peer in peers: 382 peer = raw_input("\nvoir la file d'attente de : ") 383 print "\ncommandes :\n" 384 for cmd in uucp.list_cmd(peer)[peer]: 385 print " "+str(cmd) 386 387 print "\ntransferts :\n" 388 for cmd in uucp.list_files(peer)[peer]: 389 print " "+str(cmd) 390 print '\n' 391