#!/usr/bin/env python # -*- mode: python; coding: utf-8 -*- # # liberer_ips.py # ------------- # # Copyright (C) 2011 Michel Blockelet # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. u"""Outil pour libérer des adresses IP.""" import os, sys import cPickle import dialog import time, pwd, ldap, ldap.modlist, random from time import mktime, strptime sys.path.append('/usr/scripts/gestion') from ldap_crans import crans_ldap from gest_crans import select, set_machine from whos import aff import affich_tools import user_tests db = crans_ldap() isadm = user_tests.isadm() cur_user = os.getenv('SUDO_USER') or pwd.getpwuid(os.getuid())[0] dlg = dialog.Dialog() dlg.setBackgroundTitle('Ressusciter une machine') def menu_principal(): """Menu principal de l'interface.""" choix = '' while 1: annul, choix = dlg.menu(u"Que souhaitez vous faire ?", choices=[("A",u"Ressusciter à partir d'un adhérent",u"Rechercher les anciennes machines d'un adhérent"), ("D",u"Ressusciter à partir de la date",u"Rechercher à partir de la date de suppression de la machine"), ("F",u"Ressusciter à partir d'un fichier",u"Récupérer depuis un fichier du cimetière"), ("C",u"Ressusciter un adhérent",u"Ressusciter un adhérent depuis un fichier du cimetière"), ("K",u"Ressusciter un club",u"Ressusciter un club depuis un fichier du cimetière"), ], item_help=1,title=u"Ressusciter") if annul: break if choix == 'A': # Ressusciter à partir d'un adhérent # On sélectionne l'adhérent adh = select(db, u'Adhérent duquel rechercher les anciennes machines a', mde='ro') if not adh: continue # Est-ce que c'est bien une machine de l'adhérent ? def condition(machine, date): return (int(machine.dn.split(',', 3)[1].split('=', 2)[1]) == int(adh.id()) and str(machine.proprio) == ("%s %s" % (adh.prenom(), adh.nom()))) choixmachine = choixrecherche(condition) if choixmachine != None: (machine, date) = choixmachine adh = choixadherent(machine, adh) if not adh: continue ressuscite(adh, machine) elif choix == 'D': # Ressusciter à partir de la date while 1: debut = None fin = None annul, result = dlg.inputbox(width=54, height=10, text=u"Entrez la plage de dates de recherche au format\nJJ/MM/AAAA:JJ/MM/AAAA :\n(Une des deux dates peut ne pas être spécifiée.)\n", title=u"Sélection des dates") if annul: break try: [strdebut, strfin] = result.strip().split(':', 1) # On teste la validité des dates # (strptime émet une erreur si le format est mauvais) if len(strdebut) > 0: debut = mktime(strptime(strdebut, '%d/%m/%Y')) if len(strfin) > 0: fin = mktime(strptime(strfin, '%d/%m/%Y')) + 24*60*60 break except: dlg.msgbox(text=u"Dates invalides",title=u"Sélection des dates") continue # On ne fait la recherche que si on a spécifié une date # (c'est mieux de ne pas instancier en mémoire toutes les machines) if debut != None or fin != None: def condition(machine, date): ok = True unixdate = mktime(strptime(date, '%Y-%m-%d-%H:%M')) if debut != None: ok = (unixdate >= debut) if fin != None: ok = ok and (unixdate <= fin) return ok choixmachine = choixrecherche(condition) if choixmachine != None: (machine, date) = choixmachine adh = choixadherent(machine) if not adh: continue ressuscite(adh, machine) elif choix == 'F': # Ressusciter à partir d'un fichier fichier = None while 1: annul, result = dlg.inputbox(width=54, height=12, text=u"Vous pouvez aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ", init=u"/home/cimetiere/Machine", title=u"Sélection du fichier") if annul: break try: fichier = open(result, 'r') break except: dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier") continue if fichier != None: machine = cPickle.load(fichier) adh = choixadherent(machine) if not adh: continue ressuscite(adh, machine) elif choix == 'C': # Ressusciter à partir d'un fichier fichier = None while 1: annul, result = dlg.inputbox(width=54, height=12, text=u"Vous pourrez peut-être aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ", init=u"/home/cimetiere/Adherent", title=u"Sélection du fichier") if annul: break try: fichier = open(result, 'r') break except: dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier") continue if fichier != None: adh = cPickle.load(fichier) if not adh: continue ressuscite_adherent(adh) elif choix == 'K': # Ressusciter à partir d'un fichier fichier = None while 1: annul, result = dlg.inputbox(width=54, height=12, text=u"Vous pourrez peut-être aussi exécuter le script sur le fichier\nressuscite [le fichier]\n\nFichier : ", init=u"/home/cimetiere/Club", title=u"Sélection du fichier") if annul: break try: fichier = open(result, 'r') break except: dlg.msgbox(text=u"Fichier invalide",title=u"Sélection du fichier") continue if fichier != None: club = cPickle.load(fichier) if not club: continue ressuscite_club(club) continue def choixrecherche(condition=None): """Demande les types de machines à chercher, et effectue la recherche avec la condition.""" # On sélectionne le type de machine annul, choix = dlg.menu(u"Type de machine ?", choices=[("Fixe",u"Machine fixe"), ("Wifi",u"Machine wireless"), ("Tous",u"Rechercher les deux types")], title=u"Recherche de machine") if annul: return None # On cherche les machines machines = recherche(choix == 'Fixe' or choix == 'Tous', choix == 'Wifi' or choix == 'Tous', condition) # Pas de résultat if not machines: dlg.msgbox(text=u"Aucun résultat",title=u"Recherche") return None return choixmachine(machines) def recherche(fixe=False, wifi=False, condition=None): """Recherche des machines du type demandé, et satisfaisant une condition : la fonction condition doit être de la forme condition(machine, date) et retourner True ou False selon si l'on veut avoir la machine dans la liste ou non.""" # Liste des fichiers à lire cimetiere = [] if fixe: cimetiere = map(lambda s: "/home/cimetiere/MachineFixe/" + s, os.listdir("/home/cimetiere/MachineFixe")) if wifi: cimetiere += map(lambda s: "/home/cimetiere/MachineWifi/" + s, os.listdir("/home/cimetiere/MachineWifi")) # On regarde chacun des fichiers valid = [] for fichier in cimetiere: try: machine = cPickle.load(open(fichier, 'r')) date = fichier[28:44] if condition == None or condition(machine, date): valid.append((machine, date)) except: pass return valid def choixadherent(machine, oldadh=None): """Permet de choisir l'adhérent à qui rattacher la machine.""" if oldadh == None: oldadhl = db.search(machine.dn.split(',', 2)[1])['adherent'] if not oldadhl: oldadhl = db.search(machine.dn.split(',', 2)[1])['club'] else: oldadhl = [oldadh] arg = u'--title "" ' arg += u'--menu "%s.' % machine.proprio # Est-ce que l'adhérent existe encore ? if (len(oldadhl) > 0 and machine.proprio == oldadhl[0].Nom()): annul, choix = dlg.menu(u"Le propriétaire de la machine est %s" % machine.proprio, choices=[("Garder",u"Ajouter à cet adhérent"), ("Autre",u"Ajouter à un autre adhérent")], title=u"Adhérent auquel rattacher la machine") annul = False choix = "Garder" else: annul, choix = dlg.menu(u"Cet adhérent n'existe plus dans la base.", choices=[("Autre",u"Ajouter à un autre adhérent")], title=u"Adhérent auquel rattacher la machine") if not annul: if choix == "Garder": adh = oldadhl[0] else: adh = select(db, u'Adhérent auquel ajouter la machine a', mde='ro') else: adh = None return adh def choixmachine(valid): """Choisit une machine dans une liste.""" # Pas de machines ! if len(valid) == 1: # Une seule réponse choix = valid[0] else: # Il faut choisir while 1: os.system('clear') choix = None print "Plusieurs réponses correspondant à votre requête ont été trouvées :" data = [] i = 1 for (machine, date) in valid: data.append([i, date, str(machine.__class__)[-4:], machine.nom().split('.', 1)[0], machine.mac()]) i += 1 print affich_tools.tableau(data, titre=[u'id', u'Date destruction', u'Type', u'Nom de machine', u'Adresse MAC'], largeur=[5, 16, 4, '*', 17], alignement=['d', 'c', 'c', 'c', 'c']) i = affich_tools.prompt(u'Votre choix ? (0 pour annuler) id =') try: i = int(i) except: print 'Choix invalide' continue if i == 0: break if i > len(valid): print 'Choix invalide' continue choix = valid[i-1] if choix: break if not choix: # Retour à l'interface de recherche return None return choix def ressuscite(adh, oldmachine): """Ressuscite une instance de machine.""" # On regarde quel type de machine c'était if str(oldmachine.__class__)[-4:] == 'Fixe': strmachine = u"Cette machine était une machine Fixe." strdef = 'Fixe' elif str(oldmachine.__class__)[-4:] == 'Wifi': strmachine = u"Cette machine était une machine Wifi." strdef = 'Wifi' else: strmachine = u"L'ancien type de cette machine est inconnu ..." strdef = '' # Certaines fois, on peut vouloir transformer une machine Fixe en Wifi, # et inversement (erreurs d'ajout ...) annul, choix = dlg.menu(strmachine, choices=[("Fixe",u"Ressusciter en tant que machine Fixe"), ("Wifi",u"Ressusciter en tant que machine Wifi")], default_item=strdef, title=u"Nouveau type de machine") if annul: return False if choix == 'Fixe': machine = MachineFixe(adh) elif choix == 'Wifi': machine = MachineWifi(adh) err = "" # On remet le nom try: machine.nom(str(oldmachine.nom())) except ValueError, c: err += c.args[0] + '\n' except EnvironmentError, c: err += c.args[0] + '\n' # On remet la MAC try: machine.mac(str(oldmachine.mac())) except ValueError, c: if len(c.args)>1 and c.args[1] == 1 and isadm: # Mac en double no, res = dlg.yesno(text=u"L'adresse MAC existe déjà, continuer ?", title=u"Adresse MAC") if not no: try: machine.mac(str(oldmachine.mac()), 1) except ValueError, c: err += c.args[0] + '\n' except EnvironmentError, c: err += c.args[0] + '\n' elif len(c.args)>1 and c.args[1] == 3 and isadm: # Mac douteuse no, res = dlg.yesno(text=u"L\'adresse MAC ne correspond à aucun constructeur, continuer ?", title=u"Adresse MAC") if not no: try: machine.mac(str(oldmachine.mac()), 1) except ValueError, c: err += c.args[0] + '\n' except EnvironmentError, c: err += c.args[0] + '\n' else: err += c.args[0] + '\n' except EnvironmentError, c: err += c.args[0] + '\n' # On met une IP automatique try: machine.ip('') except ValueError, c: err += c.args[0] + '\n' except EnvironmentError, c: err += c.args[0] + '\n' except RuntimeError, c: err += c.args[0] + '\n' # Des erreurs ? if err: dlg.msgbox(text=u"%s" % err,title=u"Paramètres machine") set_machine(machine) return True def ressuscite_adherent(old): """Ressuscite une instance d'adhérent""" if not isinstance(old, Adherent): dlg.msgbox(text=u"Ceci n'est pas un adhérent !", title=u"Mauvais type d'objet") return if not isadm: dlg.msgbox(text=u"Vous devez être nounou !", title=u"Droits insuffisants") return # On contourne ldap_crans data = old._data # Ajout d'une entrée dans l'historique timestamp = time.localtime() hist = "%s, %s : " % (time.strftime(date_format, timestamp), cur_user) hist += "resurrection" data['historique'].append(hist) # Entrées à vérifier : # aid, canonicalAlias, homeDirectory, mail, mailAlias, uid, uidNumber # On recherche les aid/uidNumber pris used_aid = [0] used_uidNumber = [0] for r in db.conn.search_s(Adherent.base_dn, 1, Adherent.filtre_idn): # r = ( dn, {} ) d = r[1] if d.has_key('aid'): used_aid.append(int(d['aid'][0])) if d.has_key('uidNumber'): used_uidNumber.append(int(d['uidNumber'][0])) # Nouvelle valeur pour aid (peut mieux faire) aid = max(used_aid) + random.randint(1, 10) data['aid'] = [str(aid)] dn = 'aid=%d,ou=data,dc=crans,dc=org' % aid if 'posixAccount' in data['objectClass']: # L'adhérent avait un compte, il faut changer/vérifier ses attributs uidNumber = max(used_uidNumber) + random.randint(1, 10) data['uidNumber'] = [str(uidNumber)] # Disponibilité du login (vérification sommaire) login = data['uid'][0] if os.path.exists("/home/" + login): no = dlg.yesno(text=u"Le compte %s existe déjà, continuer ?" % login, title=u"Compte existant") if no: return if True: # On croise les doigts try: modlist = ldap.modlist.addModlist(data) db.conn.add_s(dn, modlist) dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails", title=u"Fin") # Au cas où l'adhérent avait des droits db.services_to_restart('droits') # On notifie après une résurrection db.services_to_restart('mail_modif', ['uid=' + login]) except Exception, e: dlg.msgbox(text=unicode(e), title=u"Erreur") else: print data raise ValueError("debug") def ressuscite_club(old): """Ressuscite une instance d'un club""" if not isinstance(old, Club): dlg.msgbox(text=u"Ceci n'est pas un club !", title=u"Mauvais type d'objet") return if not isadm: dlg.msgbox(text=u"Vous devez être nounou !", title=u"Droits insuffisants") return # On contourne ldap_crans data = old._data # Ajout d'une entrée dans l'historique timestamp = time.localtime() hist = "%s, %s : " % (time.strftime(date_format, timestamp), cur_user) hist += "resurrection" data['historique'].append(hist) # Entrées à vérifier : # aid, canonicalAlias, homeDirectory, mail, mailAlias, uid, uidNumber # On recherche les aid/uidNumber pris used_cid = [0] used_uidNumber = [0] for r in db.conn.search_s(Club.base_dn, 1, Club.filtre_idn): # r = ( dn, {} ) d = r[1] if d.has_key('cid'): used_cid.append(int(d['cid'][0])) if d.has_key('uidNumber'): used_uidNumber.append(int(d['uidNumber'][0])) # Nouvelle valeur pour cid (peut mieux faire) cid = max(used_cid) + random.randint(1, 10) data['cid'] = [str(cid)] dn = 'cid=%d,ou=data,dc=crans,dc=org' % cid if 'posixAccount' in data['objectClass']: # L'adhérent avait un compte, il faut changer/vérifier ses attributs uidNumber = max(used_uidNumber) + random.randint(1, 10) data['uidNumber'] = [str(uidNumber)] # Disponibilité du login (vérification sommaire) login = data['uid'][0] if os.path.exists("/home/" + login): no = dlg.yesno(text=u"Le compte %s existe déjà, continuer ?" % login, title=u"Compte existant") if no: return if True: # On croise les doigts try: modlist = ldap.modlist.addModlist(data) db.conn.add_s(dn, modlist) dlg.msgbox(text=u"Résurrection effectée ! Veuillez maintenant restaurer le home et les mails", title=u"Fin") # Au cas où l'adhérent avait des droits db.services_to_restart('droits') # On notifie après une résurrection db.services_to_restart('mail_modif', ['uid=' + login]) except Exception, e: dlg.msgbox(text=unicode(e), title=u"Erreur") else: print data raise ValueError("debug") if __name__ == '__main__': if len(sys.argv) < 2: menu_principal() os.system("clear") else: for path in sys.argv[1:]: fichier = open(path, 'r') machine = cPickle.load(fichier) adh = choixadherent(machine) if adh: ressuscite(adh, machine)